3.6.1 Top-down Inference
Most of the time, types are inferred on their own and may then be unified with an expected type. In a few places, however, an expected type may be used to influence inference. We then speak of top-down inference.
Define: Expected Type
Expected types occur when the type of an expression is known before that expression has been typed, e.g. because the expression is argument to a function call. They can influence typing of that expression through what is called top-down inference.
A good example are arrays of mixed types. As mentioned in Dynamic, the compiler refuses [1, "foo"]
because it cannot determine an element type. Employing top-down inference, this can be overcome:
class Main {
static public function main() {
var a:Array<Dynamic> = [1, "foo"];
}
}
Here, the compiler knows while typing [1, "foo"]
that the expected type is Array<Dynamic>
, so the element type is Dynamic
. Instead of the usual unification behavior where the compiler would attempt (and fail) to determine a common base type, the individual elements are typed against and unified with Dynamic
.
We have seen another interesting use of top-down inference when construction of generic type parameters was introduced:
typedef Constructible = {
public function new(s:String):Void;
}
class Main {
static public function main() {
var s:String = make();
var t:haxe.Template = make();
}
@:generic
static function make<T:Constructible>():T {
return new T("foo");
}
}
The explicit types String
and haxe.Template
are used here to determine the return type of make
. This works because the method is invoked as make()
, so we know the return type will be assigned to the variables. Utilizing this information, it is possible to bind the unknown type T
to String
and haxe.Template
respectively.