Open CeylonMigrationBot opened 10 years ago
[@pthariensflame] 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>
.
[@gavinking] @pthariensflame True, that would make this problem go away.
[@RossTate] 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.
[@gavinking] @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>
.
[@RossTate] 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.
[@pthariensflame] 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>
.
[@RossTate] 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.
[@gavinking] 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.
[@gavinking] 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.[Migrated from ceylon/ceylon-spec#904]