identityless objects and the type hierarchy

Brian Goetz brian.goetz at oracle.com
Wed Nov 3 19:42:55 UTC 2021



On 11/3/2021 3:00 PM, Kevin Bourrillion wrote:
> Okay, let's stick a pin in proper-value-types (i.e. try to leave them 
> out of this discussion) for a moment...
>
> One question is whether the existing design for the bifurcated type 
> hierarchy will carry right over to this split instead. (My 
> understanding of that design is: every (non-Object) concrete class 
> will implement exactly one of two disjoint interfaces, explicitly or not.)
>
> My first thoughts were that the situation is different here: exposed 
> identity seems to be strictly (maybe?) contractually stronger than no 
> exposed identity. So here, a class being "noncommittal" /ought to/ 
> look the same as it being identityless. In theory, it should be 
> harmless for an identity class to extend an identityless class (while 
> the opposite direction is a problem).
>
> So, first, is that even right?

We went back and forth on this a few times.  A useful lens is to ask: 
how might we depend on reflecting identity-{ful,less}ness in the 
hierarchy?  These include:

     if (x instanceof IdentityObject) { ... }

     void m(IdentityObject o) { ... }

     <T extends IdentityObject> m(T t) { ... }

It is worth noting that the first is invertible (we can negate the 
condition) but the latter two are not.  Which is another way to say 
that, if anyone, anywhere, might want to write code that *requires* no 
identity, then we should consider giving them a way to do it.

(Ideally, if you're planning on (say) synchronizing on a parameter, you 
should engage the type system to ensure that an identityful object is 
passed; this is a good use of the type system.)

> Next, even if so, the Backward Default Problem strikes again. To make 
> a class identityless you would seem to need all your /supertypes/ to 
> be, first! That's hard to pull off. And `Object` itself would seem to 
> want to be marked identityless, which is obviously weird/problematic.

The superclass chain is tricky, but we've spent a lot of time shaking 
this box.  Some types are _identity-agnostic_.  These include interfaces 
that do not extend PrimitiveObject, abstract classes that meet some set 
of conditions, and Object.  The supertypes of a primitive class (and of 
an identity-agnostic class) must be identity-agnostic.

This is powerful.  For example, an interface could extend 
IdentityObject, which would effectively prohibit primitive classes from 
implementing it.  This is a way to signal "my (concrete) subtypes need 
identity."



More information about the valhalla-spec-observers mailing list