L-type, Q-type and class mirrors
Brian Goetz
brian.goetz at oracle.com
Wed Jan 12 12:27:07 UTC 2022
> Let's take a detour, and try to answer to the question, how do we do reflection on method with Q-types ?
> Given that reflection is using the class java.lang.Class, it means that we need a class that represents a L-type and a class that represent a Q-type.
Correct. In addition to all sorts of VM reasons for this, users need a
way of distinguishing between
m(Point.ref p)
and
m(Point p)
with reflection, MH.Lookup, etc.
> The class that represents a Q-type does not have to be a 'real' class, the same way int.class (Integer.TYPE) is not a real class,
> it's a mirror class that represent 'I' in the method signature, same with void.class (Void.TYPE) represent 'V'.
Correct. We've been calling these "secondary mirrors". Note that with
extended primitives, it is possible (though not required) that the
secondary mirror reflect almost everything that the primary does --
methods, fields, supertypes, etc. Alternately, they could be more like
int.class, which is pretty limited.
Unfortunately, though, we run into a user expectation problem: users
will reasonable expect that if they reflect over
m(Point p)
they will get Point.class back. Since the user views "Point" as the
primary type (Point.ref is a supporting player), they'll expect
Point.class to be the "important" mirror. This asymmetry with the
current state of affairs is a challenge.
> So the class that represents a Q-type is a mirror class synthesized by the VM at runtime.
> Given that it is synthesized, i believe it should be only accessible using a method of java.lang.Class,
> by example
> Complex.class.mirrorType() // the name "mirror" is perhaps not the best
Stepping back, what you're saying is to expose only Point.class, and
make it harder to get at the "other" mirror, such as by relegating it to
a method like Class::otherMirror. This is a reasonable move, but it
does run smack into the above problem -- that if there's one mirror,
users will expect Point.class to reflect the Point type they are most
familiar with, which is QPoint.
> I propose to introduce a new kind of primitive class, the builtin primitive class, that
Whether we call it that, or summon it by magic, we are stuck with some
form of this anyway, because of the asymmetries you've observed; the
existing int/Integer pairs have subtle differences from declared
Point/Point.ref pairs. There will have to be some special pleading for
built-in/legacy/basic primitives.
I think where you're going is some flavor of this:
special-legacy-backwards value class Integer
with-legacy-primitive int { ... }
where we declare the Integer/int pair, but do so through Integer, but
declare it to be backwards from the other primitives, where there are
only eight of these allowed.
More information about the valhalla-spec-observers
mailing list