value type hygiene
john.r.rose at oracle.com
Mon May 14 16:06:05 UTC 2018
On May 12, 2018, at 7:34 AM, Brian Goetz <brian.goetz at oracle.com> 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.
More information about the valhalla-spec-observers