Search code examples
haxeunification

Unification and implicit cast of the type parameter


class Base, and class Ext extends Base. class B<T> with typed method foo<T>(value:T)

Why B<Base>.foo doest not accept instance of B<Ext> (implicit downcast of the type parameter?) by default?

Here is an example http://try.haxe.org/#d443f

class Test {
    static function main() {

        var bExt = new B(new Ext());
        var bBase = new B(new Base());

        bBase.foo(bExt);
        //ofc 
        //bBase.foo(cast bExt);
    }
}

class B<T>
{
   public function new(v:T)
   {
   }

   public function foo(v:B<T>)
   {
      //  
   }
}

class Base {
    public function new(){}
}
class Ext extends Base {
    public function new(){
        super();
    }
}

Is there any way to trigger implicit cast of the type parameter for B.foo?


Solution

  • There are three ways to interpret and answer your question:

    1. foo(v:B<T>):

    This is your example and it doesn't compile because T isn't allowed to be be variant. It happens because of the very existence of foo and because allowing bBase.foo(bExt), that is, unifying bExt with bBase, will then allow bBaseOfbExt.foo(bBase).

    It is the fact that foo exists and that it can potentially modify the type that makes the bExt unification with bBase unsafe; you can see a similar (but maybe clearer) explanation in the manual, using arrays: type system – variance.

    2. foo(v:T):

    This is closer to what's on the body of your question (but not in the example) and it works fine.

    3. foo<A>(v:B<A>):

    Finally, if you have a type parameterized method, it also works, but you'd probably face other variance issues elsewhere.