A Tour of Morfa

Function templates

Recall the template `List` from the section on class and struct templates.

A generic function that operates on lists of elements of any type, for example counts the number of elements in a list, may be defined using a function template:

``````import advanced.templates.class_templates;

// Warning: does not terminate for cyclic lists!
public template <T>
func length(list: List<T>): int
{
return if (list == null) 0
else 1 + length(list.tail);
}

unittest
{
var list = new Ints(1, new Ints(2, new Ints(3, null)));
assert (length<int>(list) == 3);
}
``````

Here, the expression `length<int>` refers to an instance of the template `length` for the parameter `T` equal to `int`, just as `List<int>` refers to an instance of `Length` for `T` equal to `int`.

Template argument deduction for function templates

When calling a function template you may usually omit the template arguments (here `<int>`) and let the compiler infer them for you by looking at the call arguments. In the case of the above call to `length`, since the type of `list` is `List<int>` the call makes sense only `length` is instantiated for `int` as well.

``````unittest
{
var list = new Ints(1, new Ints(2, new Ints(3, null)));
assert (length(list) == 3);

// However, this wouldn't work without
// explicit instantiation with <int>:
// assert (length(null) == 0);
assert (length<int>(null) == 0);

var noInts: Ints = null;
assert (length(noInts) == 0);
}
``````

Function template argument deduction allows us to create lists using a more concise notation, while the compiler infers all the boring details:

``````public template <T>
func cons(head: T, tail: List<T>): List<T>
{
}

unittest
{
var ints = cons(1, cons(2, cons(3, null)));
assert (length(ints) == 3);
}
``````

If you are in a mood for a more fancy notation:

``````public operator :: { kind = infix, precedence = mul, associativity = right }

public template <T>
func :: (head: T, tail: List<T>): List<T>
{
}

unittest
{
var ints = 1 :: 2 :: 3 :: null;
}
``````