Haxe allows parametrization of a number of types, as well as class fields and enum constructors. Type parameters are defined by enclosing comma-separated type parameter names in angle brackets <>
. A simple example from the Haxe Standard Library is Array
:
class Array<T> { function push(x : T) : Int; }
Whenever an instance of Array
is created, its type parameter T
becomes a monomorph. That is, it can be bound to any type, but only one at a time. This binding can happen either:
new Array<String>()
) orarrayInstance.push("foo")
.Inside the definition of a class with type parameters, the type parameters are an unspecific type. Unless constraints are added, the compiler has to assume that the type parameters could be used with any type. As a consequence, it is not possible to access the fields of type parameters or cast to a type parameter type. It is also not possible to create a new instance of a type parameter type unless the type parameter is generic and constrained accordingly.
The following table shows where type parameters are allowed:
Parameter on | Bound upon | Notes |
---|---|---|
Class | instantiation | Can also be bound upon member field access. |
Enum | instantiation | |
Enum Constructor | instantiation | |
Function | invocation | Allowed for methods and named local lvalue functions. |
Structure | instantiation |
As function type parameters are bound upon invocation, they accept any type if left unconstrained. However, only one type per invocation is accepted. This can be utilized if a function has multiple arguments:
class Main { static public function main() { equals(1, 1); // runtime message: bar should be foo equals("foo", "bar"); // compiler error: String should be Int equals(1, "foo"); } static function equals<T>(expected:T, actual:T) { if (actual != expected) { trace('$actual should be $expected'); } } }
Both of the equals
function's arguments, expected
and actual
, have type T
. This implies that for each invocation of equals
, the two arguments must be of the same type. The compiler permits the first call (both arguments being of Int
) and the second call (both arguments being of String
) but the third attempt causes a compiler error due to a type mismatch.
Trivia: Type parameters in expression syntax
We often get the question of why a method with type parameters cannot be called as
method<String>(x)
. The error messages the compiler gives are not very helpful. However, there is a simple reason for that: the above code is parsed as if both<
and>
were binary operators, yielding(method < String) > (x)
.