RFR: implementation for JEP 334: JVM Constants API
brian.goetz at oracle.com
Tue May 29 20:06:46 UTC 2018
I understand why you're hammering on this issue; it seems like something
that is unnecessarily complex. So, if it can be simplified without
oversimplifying, that's great. That said, the signature is the tail,
and we shouldn't let the tail wag the dog. Ideas like "let's not have
DCD extend Constable" are tail wagging dog, so let's not go there.
The reason all the concrete subclasses of ConstantDesc implement
Constable is that we want the nominal descriptors to _themselves_ be
constants, which can further be embedded in the constant pool (this
means they can often be reconstituted more efficiently than by
generating the obvious bytecode; this is groundwork for the enhanced
constant folding work to come.) This is subtle; while ConstantDesc and
Constable are in some ways mirrors of each other, in some ways they are
not. That is, when you do:
Class aClass = ClassRef.of("java.lang.String");
ConstantDesc cd = aClass.describeConstable() // gonna be a ClassDesc
ConstantDesc cdd = cd.describeConstable() // Definitely not ClassDesc!
Here, `cd` describes a constant for a Class; `cdd` describes one for a
ClassDesc, which is a dynamic constant which, when resolved, resolves to
In turn, this is conditioned by a lot of historical baggage, such as:
there is a live object type, Class, which can represent both reference
class literals (String.class) and primitive class literals (int.class).
Both (as of 11) have a constant pool representation. However, their CP
representation is different; reference types are represented with
Constant_Class_info, whereas primitive types are represented with
condy. Therefore, they will use different kinds of ConstantDesc to
describe them. But just as we have a single Class type that describes
all runtime types, we want a single ClassDesc type that describes them
all nominally, so other APIs (like MethodTypeDesc) don't have to
propagate this unfortunate representational bifurcation. Papering over
this rift contributed to the signature complexity.
The first `? extends` is needed because we don't want to force APIs to
return _exactly_ a `ConstantDesc`; we want to allow them to return a
more decriptive subtype, if desired, as `EnumDesc` does. So we have
Optional<? extends ConstantDesc<X>> describeConstable()
and we have to fill in the X.
But its good you pressed on this, because the super-constraint actually
came from someplace else, which was totally accidental:
Class<T> extends Constable<Class<T>>
which was inconsistent with
ClassDesc extends ConstantDesc<Class<?>>
This turned out to be the constraint that was killing us, for which the
`super` was the only way out (and one that was not really correct). By
fixing this, I was able to drop the super (along with some other changes
elsewhere along the line.) So it looks like your Sunday was well-spent
(assuming all goes well downstream.)
On 5/27/2018 8:52 PM, jbvernee wrote:
> Hello (again),
> Sorry for keeping this going, but I keep thinking of new things a few
> hours later (there goes my Sunday :/).
> I'm wondering if the return type of `Constable::describeConstable` is
> actually correct. Right now it's `Optional<? extends ConstantDesc<?
> super T>>`, but why are you using `ConstantDesc<? super T>`? Since
> `ConstantDesc` is a _producer_ of `T` PECS dictates that it should use
> co-variance, i.e.: `ConstantDesc<? extends T>`, so that would make
> `Optional<? extends ConstantDesc<? extends T>>` the return type. (a
> ConstantDesc that resolves to a String can also be viewed as a
> ConstantDesc that resolves to an Object)
> That way you don't even have the problem I was trying to solve before,
> and the return type of `EnumDesc::describeConstable` (and similarly
> for `VarHandleDesc`) can be
> `Optional<DynamicConstantDesc<EnumDesc<E>>>` which is the exact type
> that is being returned, which is what is wanted right?
> On that note, you could also change the return type of
> `describeConstable` for the box types and String to return an optional
> of the type itself (since they're their own descriptor, each
> implements `ConstantDesc` of itself). For instance, for `Double` this
> would change from `Optional<ConstantDesc<Double>>` to `Optional<Double>`.
> Best regards,
> Jorn Vernee
More information about the amber-dev