value type hygiene

John Rose john.r.rose at
Mon May 14 16:06:05 UTC 2018

On May 12, 2018, at 7:34 AM, Brian Goetz <brian.goetz at> wrote:
> I get that.  What I’m saying is: boxes have a place in the user model.  We may hate them, but without them, we likely find ourselves “boxed” into a corner.  So I don’t want them to be a library convention; I want them to be understood by, say, asType().  Otherwise we’re playing whack-a-mole.  

I don't fully understand the point you make by "a library convention".  Maybe "only a
library convention unknown to the rest of the stack"?  The existing box types are
a library convention.  It's even an irregular one (int vs. Integer).   The JLS recognizes
them (in the box/unbox rules).  Following the JLS, so do asType, core reflection,

Since value types "code like a class" there are new moves for making library
conventions unavailable to primitive types, and adding an interface super seems
to be a better move, for value types, than the companion type pattern we must
use for int/Integer.

Further, we can meet many of the requirements met by the companion class pattern
by using the generic-super pattern (V <: ValueRef<V>) in the case of value types.

One requirement *not* met by using the generic-super pattern is run-time reification
of the box types, since before erasure ValueRef<Complex> and ValueRef<Point>
are different types, but to the VM they are the same type.  But I don't think that's a
deal-killer.  Maybe you see a problem with the erasure that I don't?

Specifically:  Do we really need a VT version of the reified wrapper type Integer?
That's what I'm trying to question here, at the risk of playing whack-a-mole.  There
is serious money to be saved if we can decide the companion class isn't needed
in the case of value types, even if it is necessary scaffolding for non-L-types.

It seems to me that most or all of the machinery in reflection and method handles
and the JLS for special-casing the companion classes exists to hoist primitives
into the L-descriptor world.  When the hoisting occurs to a wrapper class, many
use cases go straight up to Object itself (or to another super of a wrapper).
Others stay on the wrapper just to make a method call like toString or hashCode.
Since value types are already classes with methods, and already are L-descriptors,
it follows that they don't need wrapper types very often.

Expressing nullity is one of those residual use cases; we know it happens sometimes
but the JVM needs help calling it out as a special case.  I claim we don't need a fully
differentiated, runtime-reified wrapper type like Integer to handle those occasional
special cases.  In the JVM we just need a way to process the nullable VT instance as
an Object or an interface.  In the language an erasable static type like ValueRef<V>
works as well as a fully reified companion type like Integer.

How far should language go in healing the gap between the int/Integer pattern and
the VT/VR<VT> pattern?  Probably not too far until we are ready to fully unify the
primitives with values.  But there are simple things we could do that might help,
like making a new notation like C.BOX that connects the various types in new ways.

— John

More information about the valhalla-spec-observers mailing list