A source code template is a snippet of source code made up of fixed text and optional variable text.
Each source code template can have any number of parameters which represent placeholders for variable text in the source code snippet. Therefore, source code templates are also called parameterized source code snippets.
A template's source code snippet can be inserted anywhere in any source code file. Each time a template is used, a fixed text must be specified for each parameter of the template.
Thus, source code templates are useful whenever identical or similar source code snippets appear in source code files.
The rules below define how to define source code templates:
Each source code template is identified by a unique template identifier. A template identifier is a prefixed identifier starting with te_ as prefix. For more information about prefixed identifiers please refer to the section called “Prefixed identifier”
Each source code template is stored in a file whose name is equal to the template's identifier, and whose file name extension is osc
Thus, template foo is stored in file te_foo.osc, template bar is stored in file te_bar.osc, and so on.
The syntax of a source code template is as follows:
Table 20.1. Source code template syntax
| Production | Syntax | Links |
|---|---|---|
source_code_template |
| Chapter 20, Source code templates |
template_parameter |
| |
variable_template_source_code |
| |
source_code_template_id | "te_" ? identifier | |
template_parameter_id | "pa_" ? identifier |
Example (see section 'Example' below for explanations):
template remark_attribute
param attribute_id end
param max_length end
attribute a_{attribute_id} type:string &
check: i_{attribute_id}.item_count <= {max_length} &
error_message: "Attribute {attribute_id} exceeds {max_length} characters!" &
default: "" &
kind: variable &
setable: all end
endSource code templates can be nested.
A source code template can itself use other source code templates. There is no limit for the number of levels allowed for nested templates. However, more than 3 levels should appear rarely in practice.
A template cannot use itself directly or indirectly, as this would lead to endless loops.
The rules below define how to use source code templates:
The syntax for using a source code template is as follows:
Table 20.2. Source code template selector syntax
| Production | Syntax | Links |
|---|---|---|
template_selector | "%" ( library_selector "." ) ? source_code_template_id template_parameter_assignments ? | Chapter 20, Source code templates |
template_parameter_assignments | "<" template_parameter_assignment ( ";" ? template_parameter_assignment ) * ">" | |
template_parameter_assignment |
( template_parameter_id ":" ) ? quoted_string_literal
remark: |
Example (see section 'Example' below for explanations):
type customer_b // attributes identifier, name, etc. (not shown here) %remark_attribute<attribute_id: "remark"; max_length: "256"> end
A source code template can be used any number of times in any location of any source code file.
Source code templates support one of the most important rules for maintainable code:
Any knowledge should be defined at one place only!
This rule is also commonly known as the DRY principle, which stands for [Don't repeat yourself!]. It was published by Andrew Hunt and David Thomas in their great book The Pragmatic Programmer (ISBN 0-201-61622-X).
Source code templates should not be overused. More specifically, they should never be used when source code duplication can be avoided by other means of the language.
For example:
Numeric constants (such as pi = 3.1415) should not be defined as source code templates, but as service attributes.
Source code templates should not be used as a replacement for utility commands. For example, if several scripts need a loop that displays items in a list, this functionality should be provided by a service command, instead of a source code template.
Suppose an ERP application with types customer, supplier and product. Each one of these types has an attribute remark (or note), which is a string limited to a certain number of characters, and used to save any text with a customer, supplier or product object. The types could be defined as follows:
type customer_a
// attributes identifier, name, etc. (not shown here)
attribute remark type:string &
check: i_remark.item_count <= 256 &
error_message: "Attribute 'remark' exceeds 256 characters" &
default: "" &
kind: variable &
setable: all end
endtype supplier_a
// attributes identifier, name, etc. (not shown here)
attribute remark type:string &
check: i_remark.item_count <= 256 &
error_message: "Attribute 'remark' exceeds 256 characters" &
default: "" &
kind: variable &
setable: all end
endtype product_a
// attributes identifier, description, etc. (not shown here)
attribute note type:string &
check: i_note.item_count <= 2048 &
error_message: "Attribute 'note' exceeds 2048 characters" &
default: "" &
kind: variable &
setable: all end
endIt is easy to see the code duplication in the above types. To avoid this, we can define the following source code template and store it in file te_remark_attribute.osc:
template remark_attribute
param attribute_id end
param max_length end
attribute a_{attribute_id} type:string &
check: i_{attribute_id}.item_count <= {max_length} &
error_message: "Attribute {attribute_id} exceeds {max_length} characters!" &
default: "" &
kind: variable &
setable: all end
endNow this template can be used in all 3 types:
type customer_b // attributes identifier, name, etc. (not shown here) %remark_attribute<attribute_id: "remark"; max_length: "256"> end
type supplier_b // attributes identifier, name, etc. (not shown here) %remark_attribute<attribute_id: "remark"; max_length: "256"> end
type product_b // attributes identifier, name, etc. (not shown here) %remark_attribute<attribute_id: "note"; max_length: "2048"> end
Code duplication has disappeared.
The template can of course be reused in other types.
Maintenance has become easier, because in case of any changes with the attribute, there is only one place to change. For example, if the error message in case of too many characters has to be changed, we only have to modify file te_remark_attribute.osc.