Sergey pointed out this additional benefit of RefObject: code that really doesn’t want to deal with values, or pay any of the taxes that arise from the fact that values are Object, such as acmp overhead.
> On 4/8/19 12:58 PM, Brian Goetz wrote: >> 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. >> >> >>