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.