On May 12, 2018, at 7:34 AM, Brian Goetz <brian.go...@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, etc. 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