I'm wondering why the following Haxe code compiles:
class Test<T> { // 1
var l:List<Dynamic> = new List<Dynamic>(); // 2
public function new() {} // 3
public function add(d:Dynamic):Void { l.add(d); } // 4
public function get():T { return l.pop(); } // 5
public static function main() { // 6
var t:Test<Int> = new Test<Int>(); // 7
t.add("-"); // 8
trace(t.get()); // 9
} // 10
}
The compilation problem I see:
As seen in line 1, this class has a type parameter T
. In line 7, it is specified that T
is an Int
. So the get()
function (line 5) should only return an Int
. However - magically - this function returns a String
(line 9).
So ... why doesn't the compiler complain about this?
A dynamic value can be assigned to anything; and anything can be assigned to it.
According to the Haxe manual: https://haxe.org/manual/types-dynamic.html
Since l
is a List<Dynamic>
, the result of l.pop()
will also be Dynamic
. This will be implicitly cast to Int
when it is returned in get()
.
I think the runtime behavior when tracing the value out at line 9
would depend on the Haxe target.
If you change l
into a List<T>
and make add()
take a parameter of type T
, then the compiler would complain. Try this: https://try.haxe.org/#11327
class Test<T> { // 1
var l:List<T> = new List<T>(); // 2
public function new() {} // 3
public function add(d:T):Void { l.add(d); } // 4
public function get():T { return l.pop(); } // 5
public static function main() { // 6
var t:Test<Int> = new Test<Int>(); // 7
t.add("-"); // 8 - this won't compile anymore
trace(t.get()); // 9
} // 10
}