Tag Archives: Embeds

Template Tips #3 – #ATEND vs #AT(%AfterGeneratedApplication)

It looks like the embed %AfterGeneratedApplication is a very popular embed these days.
We already talked about it in the Template Tips #2 post where we compare it with the #AT(%ProgramEnd). Now we’ll compare #AT(%AfterGeneratedApplication) with #ATEND, and we’ll explain which of these is appropriate for a given task.

Why do we compare #ATEND with #AT(%AfterGeneratedApplication) ?
Because both of these are executed at the end of the code generation process (when we click on the Generate button).
Some 3rd Party Templates have the need to execute code that requires the App to be have been generated, and you’ll find they make use of #ATEND or #AT(%AfterGeneratedApplication).

All of the templates support #ATEND, but we’ll focus on the #APPLICATION #ATEND embed.
The #ATEND is comparable to a Destructor of a class, it is executed at the end of a templates code generation cycle, and the purpose is typically to execute some clean up code. When I mention clean up code I’m not talking about generating backups, creating extra files, or doing some extra  processing, etc. I’m talking about cleaning up template symbol values. Any other processing should not be executed in the #ATEND.

One of the reasons additional processing should not be executed in the #ATEND is that the #ATEND is similar to a Class Destructor, and that means the scope of the template is already ending, so just like in any other Class Destructor. you should not be creating new instances of anything at that point.

Another reason, that is more related to the templates is the Embeditor. What does the Embeditor have to do with the #APPLICATION #ATEND?
Well if you inspect the #APPLICATION code closely you will see that there is one magic part that make the Embeditor work.

I’m talking about this code:

#IF (%EditProcedure)            #! Special for editing embedded source in context
  #CREATE(%EditFilename)
  #FIND(%ModuleProcedure,%EditProcedure)
  #FIX(%Procedure,%ModuleProcedure)           #! Fix current procedure
  #MESSAGE('Generating Module:    ' & %Module,1) #! Post generation message
  #MESSAGE('Generating Procedure: ' & %Procedure,2) #! Post generation message
  #GENERATE(%Procedure)                       #! Generate procedure code
  #COMMENT(60)                                #!Set comment alignment to column 60
  #CLOSE
  #ABORT                                      #!Stop execution of any other code
#ENDIF

Yes, the Embeditor code is just the #GENERATION of the procedure with a little bit of magic.

Because this code is executed in the #APPLICATION section of the template we are expecting the #APPLICATION #ATEND to be executed.
Actually everything would be executed if it was not for the #ABORT at the end of the above code.
So if you are using the #ATEND, you are not only adding code to the equivalence of a Class Destructor, but you are also adding code that will always be executed unless you check for the value of the %EditFilename symbol. If the value of %EditFilename is null then you can be sure that you are in regular code generation, and not in the Embeditor generation. This is a very important point.

Where does the #AT(%AfterGeneratedApplication) fit into all this code generation?
Well the #EMBED(%AfterGeneratedApplication) is located at the end of the #APPLICATION template, it’s the last code to be generated before the #ATEND, but the big difference is that it only executes when we are generating the #APPLICATION during regular code generation. The execution of that embed will not happen on the Embeditor generation because of the #ABORT that we already mentioned.

The conclusion, if you need to execute code at the end of the Application generation process, I always recommend the use of the #AT(%AfterGeneratedApplication) instead of the #ATEND. And always try to use a PRIORITY, that will make other templates play nice with yours.

Template Writing Tips

This is one of many posts to come with advice and tips about things you should do, and things to avoid, when writing Templates. It is intended to help developers who write templates to validate their templates, and to implement some best practices to ensure the templates they deliver work as expected.

The template language is very strict in its syntax, and blank spaces/lines can have a big impact. Spaces where they are not expected are evil. A blank line in the templates will generate a blank line in the generated code, but where that blank line lands in the generated code depends upon where that blank line is within the template code.

Some areas of a template are not meant to generate code, for example #PROMPTs representing the UI. Some templates, like an Extension template, are not supposed to contain any generated code except within #ATs where the code is inserted into an #EMBED.

If a blank line is found in a template, but in a place that is not correct, like between #PROMPTs, or outside a #AT in an Extension template, the code generator will push that line into the generated code, but because the blank line was in an incorrect location there is no explicit place to insert that blank line, and it will add it at the beginning of the block of generated code. To summarize, blank lines in a template are good, except when they are somewhere they are not supposed to be.

Blank lines intended to make the template code easier to read should be always be replaced with #! in column 1 (or just removed). There isn’t a blank line “statement” in the template language, and the reason for that is so that you don’t not mix template language code, with generated output text. Using something like #!———- is much better than a blank line, better in that it is safer and it is more visual.

Some places where a blank line should not be placed:

In any template between a #PROMPT or any other UI code (#SHEET,#TAB,etc.).
In #EXTENSION templates any blank line outside an #AT/#ENDAT block is incorrect.
In a #UTILITY template any blank line outside the scope of an #OPEN or #CREATE is incorrect.
In any template, any blank line used as a separator between #DECLARE statements or as a separator between any other statement is incorrect.

As a golden rule, if the blank line is not intended to be output to the generated code, then the blank line should be replaced by a #! in column 1, or just removed.