Templates are to classes what classes are to objects: blueprints for classes that can be instantiated multiple times with parameterized values to create multiple specialized classes that share the same general functionality.
Slag's templates are true templates (not generics). They are much more powerful than C++ templates because they can be specialized with arbitrary code, not just type names. Their most common application is to allow data structures to be adapted to various data types.
This example shows the basic idea behind templates.
local Int32Pair int_pair(3,5) local Real64Pair real_pair(3.0,5.0) println( "$ $" (int_pair,real_pair) ) # prints: (3,5) (3.0000,5.0000) ... class Int32Pair( Int32 first, Int32 second ) method to_String.String: return "($,$)" (first,second) endClass ... class Real64Pair( Real64 first, Real64 second ) method to_String.String: return "($,$)" (first,second) endClass
Note how the "Pair" classes only differ by the datatype used. We can use a template to make the datatype a parameter and implicitly create two classes from the same template:
local Pair<<Int32>> int_pair(3,5) local Pair<<Real64>> real_pair(3.0,5.0) println( "$ $" (int_pair,real_pair) ) # prints: (3,5) (3.0000,5.0000) ... class Pair<<$DataType>>( $DataType first, $DataType second ) method to_String.String: return "($,$)" (first,second) endClass
- "Pair<<$DataType>>" is called a templated class and "$DataType" is called a placeholder value. You can specify more than one ("SomeType<<$DataType,$alpha,$beta>>").
- Placeholder values must start with a leading '$'. Case does not matter as long as it is consistent.
- "Pair<<Int32>>" and "Pair<<Real64>>" are called template instances and the "Int32" and "Real64" are called substitution values.
- A template instance is just a regular class at the end of the day. You just didn't have to duplicate all the source code manually.
- The example above creates two distinct classes: Pair<<Int32>> and Pair<<Real64>>. They are unrelated - both are instanceOf class Object; they have no other common base type. You could just as easily think of them as "Int32Pair" and "Real64Pair" - the code produced is the same in the original and the templated example.
Templates can be used in a macro style, meaning that you can insert arbitrary code as the substitution value.
class OpTest method init: local Op<<+>> plus() local Op<<*>> times() println( plus.apply(3,5) ) # prints: 8 println( times.apply(3,5) ) # prints: 15 endClass class Op<<$op>>() method apply( Int32 lhs, Int32 rhs ).Int32: return lhs $op rhs endClass