Open FroMage opened 10 years ago
This is related to ceylon/ceylon.language#329
I think it's perfectly fine that adding/removing an of
clause is not BC -- adding an extends
or satisfies
clause isn't, afterall.
Well, the issue is that if we compile a call site to Type.$caseValues$()
because it has case values, and then later we remove the case values, the call site is going to have an error rather than an empty sequence as the metamodel would return.
If a class Foo
satisfies Bar
and is assigned to a Bar
somewhere and Foo
later changes to no longer satisfy Bar
then you end up with either a compile or link time error. The only question is whether the compile time error will be caught by the typechecker (I agree that we should avoid this being a backend error).
Alternatively what's stopping us from using a hidden interface (like ReifiedType
)? It would then be trivial to write a little method in Metamodel
or Util
which did the instanceof
and returned the result, or threw a meaningful exception.
Ah! Now that's brilliant! Thanks for the idea :)
Argg… no that doesn't work. It needs to be a static
method :(
Moving to 1.2 unless we find a good way to do this.
It's basically the same problem that Java faces with it's Enum
: In order to implement the static Enum.valueOf()
it seems to be happy to reflectively invoke the static values()
method of the Enum
implementation.
So we could still use a hidden interface as a marker (or I guess we could use the existing cases annotation) and have the Util method invoke reflectively only when we know it's an enumerated type.
Yes but the JVM can do magic for those. Hey, perhaps this should be resolved with an indy call?
Yes but the JVM can do magic for those.
WDYM?
Ah sorry, I didn't read properly. Yes, Enum.valueOf
needs reflection to work, but not it's redefined in each enum subtype, and that one doesn't need reflection.
Also if E
is not an enum anymore (binary-incremental) then E.values()
will throw, which is not acceptable in our case.
I think you're still misunderstanding (or I'm misunderstanding you; I'm pretty sure there's a misunderstanding here somewhere).
I'm saying we generate a static
method in each type with case values, and that in some method in Util
we:
j.l.Class
for the given type has the @CaseTypes
annotation
[]
or whateverSo if the once-enumerated type ceases to be be enumerated at runtime that's OK.
AFAICS that's the best we can do.
Well, no, that's still using reflection so it's not optimal. Java's E.values()
does not use reflection so that's what we're going to be compared against. I think we should use indy for that.
But Java's E.values()
is a static invocation, of course it's not reflective. But sure, use indy if you want.
I know it's not reflective, I'm saying that we need to optimise `E
.caseValuesin Ceylon to something as efficient as
E.values()` in Java.
Riiight. Well, yes you're going to want to use indy for this so you have some control at link time.
That's what I said, didn't I? ;)
We should generate a method
$caseValues$()
in every toplevel type which has case values that returns a sequence of those values, so we can substitute any calls to`Type
.caseValueswith
Type.$caseValues$()` to bypass the metamodel entirely.Now, the problem is that either we create that method for every type, even those who don't have case values, and we're binary/incremental compatible. Or we do it just for those which do have case values, and substitute an empty sequence
[]
on call sites, but then we're not binary/incremental compatible.Not quite sure how best to proceed here. I don't quite like adding this method to every toplevel type.