A couple of recent blogs have mentioned the feature of e templates, which was added to Specman relatively recently. If you are used to e macros -- the feature that has existed in the e language almost since forever -- you may wonder if it's not just the same concept in a different form. In other words, is it really essential to use templates, when you can use macros to achieve exactly the same result?
In some sense, templates are indeed similar to define-as macros. Both define parameterized code, which is instantiated by substituting parameters. In principle, a statement macro can be used for the purpose of defining a parameterized type, if it has type syntactic arguments and a struct definition in its replacement code. Calling that macro will create a specific struct, which is analogous to creating a template instance.
However, there are several differences, which make using templates preferable. Let's illustrate the most important of these differences on a simple example. Assume the following template definition:
template struct stack of <type> {
private items: list of <type>;
pop(): <type> is {
if items.is_empty() { error("Stack is empty") };
return items.pop();
};
push(x: <type>) is {
items.add(x);
};
};
Given the above template, you can write things like "stack of int,'" "stack of packet" anywhere in the code, and the corresponding template instance type will be created automatically. Further, if you refer the same template instance more than once, Specman automatically determines whether the instance already exists, so it is created only once. For example, the following code creates "stack of int" type once, though it is used twice in the code:
extend sys {
x: stack of int;
y: stack of packet;
run() is also {
var a: stack of int;
......
};
};
If templates had not existed in the language, we could have implemented the same with a macro, for example:
define <stack'statement> "stack_decl of <type>" as {
struct stack_<type> {
private items: list of <type>;
pop(): <type> is {
if items.is_empty() { error("Stack is empty") };
return items.pop();
};
push(x: <type>) is {
items.add(x);
};
};
};
However, no automatic instantiation would occur, so if we needed to instantiate this parameterized type with a certain type as the parameter, we would have to declare it explicitly. So, the above template usage example would appear as follows:
stack_decl of int;
stack_decl of packet;
extend sys {
x: stack_int;
y: stack_packet;
run() is also {
var a: stack_int;
......
};
};
Note that the stack_decl statement must appear exactly once for each "instance." Otherwise we would get a compilation error due to a duplicate struct declaration.
Another drawback of using a macro like the above is that we had to invent our own syntax both for the declaration statement - "stack_decl of xxx" and for the type name itself - "stack_xxx". The syntax for templates, on the other hand, is already given to us by the language.
Yuri Tsoglin
Specman R&D, e Language team.