Some high-level feedback from me:
I think the idea is reasonable. In other circles, we might call this a
"milestone". Should we define a first milestone that we're willing to commit to
strongly, with some sort of distribution channel (something better than
build-your-own-JDK) and some level of support commitment to users who want to
get their hands dirty? Sure, absolutely.
There are some design decisions that surprise/confuse me. Basically, this is me
saying "YAGNI" over and over again:
1) Automatic boxing adds tons of complexity, and I don't see the benefit. The
feature eliminates boilerplate and supports migration, but I'm not looking for
either of those in a minimal first step. We're talking about a handful of value
types, which can easily be defined like this:
class Val {
public final int i;
public final int j;
public static ValBox box(Val x) { return new ValBox(x); }
public static Val unbox(ValBox b) { return b.x; }
}
class ValBox implements Foo {
public final Val x;
public ValBox(Val x) { this.x = x; }
}
Get rid of boxes, and you can get rid of interfaces, default methods, automatic
conversions, constructors, ...
2) Instance methods also add tons of complexity. Again, they only exist for
convenience and migration. If static methods can operate on value types, that's
all you need. No longer necessary to deal with bytecode written to operate on
an L-typed 'this' and somehow re-interpret it for a Q-typed 'this'. No longer
necessary to deal with Object methods (because no operation supports invoking
them).
(If we really do want instance methods, I suggest making 'this' Q-typed to
begin with, not diverting resources into figuring out how to make L-typed
instance methods efficient.)
3) The minimal feature set for basic operations -- field getters, default
value, withers, comparison, arrays -- is a class (e.g., ValueTypeSupport) with
bootstrap methods that can be called via invokedynamic. No need to touch
MethodHandles.Lookup, etc.
More generally, why so much attention given to reflection? Sure, you need class
objects to represent all the JVM's types. But member lookup? Fields, Methods,
Constructors? These do not seem necessary.
If I squint, I can kind of see how the idea is that somebody might want to
write reflective code to operate on values, since they don't have language
support. But almost everything has to be boxed when using these libraries,
which means if you care about performance (which is why you're using this
prototype), you're going to be spinning bytecode to do your low-level
operations. If this is the use case, I think a better use of resources would be
to surface Q types in the language.
4) I don't love hacking CONSTANT_Class to encode new types, but I can probably
live with it. My preference is to design it the "right" way -- however we
envision these ultimately being expressed -- rather than this intermediate step
in which everybody learns to interpret some new syntax, only to turn around and
deprecate that syntax a little while later. (I realize it's probably easier to
change string formats than it is to add a new constant pool form.)
I don't think it's necessary to support Q types as the receivers of
CONSTANT_Fieldrefs and CONSTANT_Methodrefs. The receiver can be a vanilla
CONSTANT_Class, and the client (in this case, the 'vgetfield' API point) can
figure out what to do with the resolved reference.
—Dan