Open andyli opened 5 years ago
Unless I am missing something, I think it's expected since haxe.extern.EitherType is meant for externs likely doing their own runtime checks, so it's up to your test()
function to call f
appropriately.
I don't think type soundness has anything to do with designing for extern usage or not.
It is simply unsound for A->Void
to unify with EitherType<A,B>->Void
. It's similar to the case as follows:
var f:Float->Void = function(n:Int) {}; // can't compile, n : Int -> Void should be Float -> Void
If I want something that can accept both A->Void
and B->Void
, I can write EitherType<A->Void, B->Void>
.
I would have said it's more similar to var f:Int->Void = function(i:Float) {};
(or var f:B->Void = function(a:A) {};
with B extends A), which compiles.
Either way I now see your point, but it does not seem to me to be possible to handle this specific case without breaking many things if the above examples are indeed the same thing.
more similar to var f:Int->Void = function(i:Float) {}; (or var f:B->Void = function(a:A) {}; with B extends A)
No, they are not similar, but exactly the opposite. Function types are contravariant, which means A->Void
can unify with B->Void
iff B
unifies with A
, but not the opposite.
var f:Float->Void = function(n:Int) {}; //can't compile, and it's correct for the compiler not to compile
var f:Int->Void = function(f:Float) {}; //compiles, and it's correct too
I agree that this violates variance because the EitherType
is the more general type.
Seems like I understood it backwards, sorry about that :confused:
If I apologized every time I got tripped by function argument variance you'd think I was Canadian.
The underlying problem here is that EitherType has to T1 to T2
which makes it unify in this direction. I'm not sure if we could just change that...
Shouldn't we check that the argument of the closure is compatible with every to
of the abstract?
Is that even possible? If that was the case then we wouldn't need the abstract in the first place...
Probably possible in some rare situations with similar abstract. E.g. Either3<T1,T2,T3>
I think the
test()
call shouldn't type-check. i.e.Int->Void
shouldn't unifies withhaxe.extern.EitherType<Int,String>->Void
.