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