RefObject and ValObject

Brian Goetz brian.goetz at
Mon Apr 8 19:58:38 UTC 2019

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 values.  

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-experts mailing list