RefObject and ValObject

Daniel Heidinga Daniel_Heidinga at
Fri Apr 12 15:16:52 UTC 2019

During the last EG call, I suggested there are benefits to having both RefObject and ValObject be classes rather than interfaces.

Old code should be able work with both values and references (that's the promise of L-World after all!). New code should be able to opt into whether it wants to handle only references or values as there are APIs that may only make sense for one or the other. A good example of this is java.lang.Reference-subtypes which can't reasonably deal with values. Having RefObject in their method signatures would ensure that they're never passed a ValObject. (ie: the ctor becomes WeakReference(RefObject o) {...})

For good or ill, interfaces are not checked by the verifier. They're passed as though they are object and the interface check is delayed until invokeinterface, etc. Using interfaces for Ref/Val Object doesn't provide verifier guarantees that the methods will never be passed the wrong type. Javac may not generate the code but the VM can't count on that being the case due to bytecode instrumentation, other compilers, etc.

Using classes does provide a strong guarantee to the VM which will help to alleviate any costs (acmp, array access) for methods that are declared in terms of RefObject and ensures that the user is getting exactly what they asked for when they declared their method to take RefObject. 

It does leave some oddities as you mention:
* new Object() -> returns a new RefObject
* getSuperclass() for old code may return a new superclass (though this may be the case already when using instrumentation in the classfile load hook)
* others?

though adding interfaces does as well:
* getInterfaces() would return an interface not declared in the source
* Object would need to implement RefObject for the 'new Object()` case which would mean all values implemented RefObject (yuck!)

Letting users say what they mean and have it strongly enforced by the verifier is preferable in my view, especially as getSuperclass() issue will only apply to old code as newly compiled code will have the correct superclass in its classfile.


-----"valhalla-spec-experts" <valhalla-spec-experts-bounces at> wrote: -----

>To: valhalla-spec-experts <valhalla-spec-experts at>
>From: Brian Goetz 
>Sent by: "valhalla-spec-experts" 
>Date: 04/08/2019 04:00PM
>Subject: RefObject and ValObject
>We never reached consensus on how to surface Ref/ValObject. 
>Here are some places we might want to use these type names:
> - Parameter types / variables: we might want to restrict the domain
>of a parameter or variable to only hold a reference, or a value: 
> void m(RefObject ro) { … }
> - Type bounds: we might want to restrict the instantiation of a
>generic class to only hold a reference (say, because we’re going to
>lock on it):
> class Foo<T extends RefObject> { … }
> - Dynamic tests: if locking on a value is to throw, there must be a
>reasonable idiom that users can use to detect lockability without
>just trying to lock:
> if (x instanceof RefObject) {
> synchronized(x) { … }
> }
> - Ref- or Val-specific methods. This one is more vague, but its
>conceivable we may want methods on ValObject that are members of all
>There’s been three ways proposed (so far) that we might reflect these
>as top types: 
> - RefObject and ValObject are (somewhat special) classes. We spell
>(at least in the class file) “value class” as “class X extends
>ValObject”. We implicitly rewrite reference classes at runtime that
>extend Object to extend RefObject instead. This has obvious
>pedagogical value, but there are some (small) risks of anomalies. 
> - RefObject and ValObject are interfaces. We ensure that no class
>can implement both. (Open question whether an interface could extend
>one or the other, acting as an implicit constraint that it only be
>implemented by value classes or reference classes.). Harder to do
>things like put final implementations of wait/notify in ValObject,
>though maybe this isn’t of as much value as it would have been if
>we’d done this 25 years ago. 
> - Split the difference; ValObject is a class, RefObject is an
>interface. Sounds weird at first, but acknowledges that we’re
>grafting this on to refs after the fact, and eliminates most of the
>obvious anomalies. 
>No matter which way we go, we end up with an odd anomaly: “new
>Object()” should yield an instance of RefObject, but we don’t want
>Object <: RefObject for obvious reasons. Its possible that “new
>Object()” could result in an instance of a _species_ of Object that
>implement RefObject… but our theory of species doesn’t quite go there
>and it seems a little silly to add new requirements just for this. 

More information about the valhalla-spec-observers mailing list