Why doesn't the Haxe compiler complain when returning a Dynamic (String) from a function with a generic (Int) return type?

Viewed 146

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?

1 Answers

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
}
Related