"dynamic" instantiations of generic types
See original GitHub issueCurrently we don’t support anything exactly like:
- Java’s raw types
- Dart’s
dynamic
instantiations of generic types - TypeScript
any
instantiations of generic types
It seems to me, that Java raw types, Dart dynamic
instantiations, and TypeScript any
instantiations are actually all very semantically similar, and could be treated in the same way by Ceylon.
(That’s assuming I understand the semantics of any
in TypeScript and how it maps to Ceylon, @lucaswerkmeister can tell me if I’ve misunderstood it.)
Currently we use the covariant instantiation X<out Object>
for a Java raw type X
, which is very reasonable, and arguably “better”, since it is sound, whereas raw types are unsound. But it has the disadvantage that you can’t do everything with an X<out Object>
that you can do with a raw X
, and, although we have not run into any cases like this yet, in principle this could make it harder to use some Java APIs.
Furthermore, AFAICS, X<out Object>
doesn’t really work well as a replacement for X<dynamic>
(or X<any>
) since unadorned JavaScript objects aren’t instances of Ceylon’s Object
type.
There’s two different techniques I can think of for introducing a reasonable mapping of X<dynamic>
:
- Make all non-
null
values instances of Ceylon’sObject
type, thus making assignment of adynamic
value toObject
legal outsidedynamic
blocks. This would, I suppose, necessitate some magic in the JS backend to make every value respond tostring
,equals()
andhash
. (But that’s in principle possible, right @chochos?) - Allow
dynamic
as a type argument.
In fact, it might be advantageous to do both 1 and 2.
Thoughts?
Issue Analytics
- State:
- Created 7 years ago
- Comments:9 (7 by maintainers)
Top GitHub Comments
So here are the questions to ask yourself:
Should
Array<dynamic>
be assignable toArray<Object>
? ShouldArray<String>
be assignable toArray<dynamic>
? What are the semantics of the above two operations? What does (in non-Ceylon syntax)new Array<dynamic>(...)
mean?After lots of consideration, here’s what we came up with:
dynamic
does not exist at run time.new Array<dynamic>(...)
is an invalid expression.dynamic
should be interpreted as “any type that will make the program type check”.Array<String>
is assignable toArray<dynamic>
, which is itself assignable toArray<Object>
.Array<dynamic>
is assigned to anArray<Object>
, a run-time check is inserted to assert that the specific array instance is in fact anArray
ofObject
.There are a lot more questions to ask, so here’s the running intuition. Type checkers are pessimistic; they only accept a program if they know there won’t be any run-time type errors.
dynamic
is a way for programmers to specify they want optimistic behavior: a program should be accepted if it’s possible there won’t be a run-time type error. Thus in a sense it only affects compile-time behavior. Consequently, there is nodynamic
type at run time. However, the run-time system relies on type safety; thus run-time “optimism checks” need to be inserted where the type checker was optimistic in a way that the run-time system needs to double check. Sometimes these checks might be casts, and other times they might be something like dynamic method lookups. Anyways, we’ve found that this general strategy can be implemented efficiently, although we haven’t experimentally analyzed generics yet.@RossTate
Right, distinguishing these two behaviors is precisely the purpose of
dynamic
blocks in Ceylon.Well, that’s not precisely right on the JavaScript platform, where you have values which really don’t have a type at runtime. (On the JVM it’s the correct model, however.)
Right, that’s exactly how Ceylon treats all this.