Open gavinking opened 10 years ago
Of course, things here (and elsewhere) would be much simpler if Ceylon had "bidirectional projections", perhaps with the syntax you gave in the language design FAQ: ArrayList<Foo>|ArrayList<Bar>
would be a subtype of ArrayList<out Foo|Bar in Foo&Bar>
.
@pthariensflame True, that would make this problem go away.
The two general solutions I can see for this are either adopting in out
or making the type of an attribute of a union of types be the union of the types of the attribute for those types.
@RossTate You just look up the type hierarchy until you notice that size
is actually refining a declaration of the covariant interface List
, which does have the principal instantiation List<Foo|Bar>
.
Right, but in general that might not be possible. I believe that technique will arrive at the same/equivalent solution as both of mine whenever it applies, but it won't always be able to apply where as mine will.
Oddly enough, Ceylon('s type system) can already partly support this. The existing system of projections would allow us to simply say that the compiler should treat any read-access of ArrayList<Foo>
as a read-access of ArrayList<out Foo>
, and it should likewise treat any write access of ArrayList<Foo>
as a write-access of ArrayList<in Foo>
.
You need both in
and out
in one if you're gonna solve this with use-site variance because an attribute may itself return an invariant usage of the type parameter.
FTR, in Ceylon 1.2, I made the code above compile, by forming the supertype instantiation ArrayList<out Foo|Bar>
. This isn't of course totally correct because it privileges covariance over contravariance, and thus list.add(fooAndBar)
doesn't compile.
I guess I could get even closer to a "correct" solution by inspecting the operation to see if the type parameter occurs covariantly or contravariantly in its signature and using that information to decide whether to use ArrayList<out Foo|Bar>
or ArrayList<in Foo&Bar>
, though of course that doesn't help much in the less common case where the type parameter occurs both covariantly and contravariantly in the signature of the operation.
Currently, things as simple as this:
Result in errors because
size
resolves toArrayList.size
, and there is no principal instantiation ofArrayList
. Of course, the typechecker should be smart enough to look atList.size
, which is something it will generally in other cases.