A couple of comments on the encoding and questions related to descriptors.

>
> JVM proposal:
>
> - Same conceptual framework.
>
> - Classes can be ACC_VALUE, ACC_IDENTITY, or neither.
>
> - Legacy-version classes are implicitly ACC_IDENTITY. Legacy interfaces are 
> not. Optionally, modern-version concrete classes are also implicitly 
> ACC_IDENTITY.

Maybe this is too clever, but if we added ACC_VALUE and ACC_NEITHER
bits, then any class without one of the bits set (including all the
legacy classes) are identity classes.

>
> (Trying out this alternative approach to abstract classes: there's no more 
> ACC_PERMITS_VALUE; instead, legacy-version abstract classes are automatically 
> ACC_IDENTITY, and modern-version abstract classes permit value subclasses 
> unless they opt out with ACC_IDENTITY. It's the bytecode generator's 
> responsibility to set these flags appropriately. Conceptually cleaner, maybe 
> too risky...)

With the "clever" encoding, every class is implicitly identity unless
it sets ACC_VALUE or ACC_NEITHER and bytecode generators have to
explicitly flag modern abstract classes.  This is kind of growing on
me.

>
> - At class load time, we inherit value/identity-ness and check for conflicts. 
> It's okay to have neither flag set but inherit the property from one of your 
> supers. We also enforce constraints on value classes and "neither" abstract 
> classes.
>
> ---
>
> So how does this score as a replacement for the list of features enabled by 
> the interfaces?
>
> - Dynamic detection: 'obj instanceof ValueObject' is quite straightforward; 
> if we can replace that with 'obj.isValueObject()', that feels about equally 
> useful. (I'd be more pessimistic about something like 
> 'Objects.isValueObject(obj)'.)
>
> - Subclass restriction: 'implements IdentityObject' has been replaced with 
> the 'identity' modifier. Complexity cost of special modifiers seems on par 
> with the complexity of special rules for inferring and checking the 
> superinterfaces. I think it's a win that we use the 'value' modifier and 
> "value" terminology for all kinds of classes/interfaces, not just concrete 
> classes.
>
> - Variable types: I don't see a good way to get the equivalent of an 
> 'IdentityObject' type. It would involve tracking the 'identity' property 
> through the whole type system, which seems like a huge burden for the 
> occasional "I'm not sure you can lock on that" error message. So we'd 
> probably need to be okay letting that go. Fortunately, I'm not sure it's a 
> great loss—lots of code today seems happy using 'Object' when it means, 
> informally, "object that I've created for the sole purpose of locking".

Do method parameters also fall under this case?  To pick on our
favourite example, how would we use the type system to adapt the
descriptor for WeakReference::<init> so it wouldn't accept Values?
Are we willing to give up on putting the constraints in the type
system given that interfaces are checked on use (ie: invokeinterface)
rather than by the verifier?

>
> - Type variable bounds: this one seems more achievable, by using the 'value' 
> and 'identity' keywords to indicate a new kind of bounds check ('<identity T 
> extends Runnable>'). Again, it's added complexity, but it's more localized. 
> We should think more about the use cases, and decide if it passes the 
> cost/benefit analysis. If not, nothing else depends on this, so it could be 
> dropped. (Or left to a future, more general feature?)

Similar to the question above, how would this be reflected in the
method descriptor?  `<identity T extends Runnable>` would erase to
Runnable?  If it doesn't get expressed somewhere that the VM can take
action on it, I think it will give developers a false sense of
security regarding the method's invariants and encourage them to skip
the `!obj.isValueObject()` checks in these methods.

>
> - Documentation: we've lost the handy javadoc location to put some 
> explanations about identity & value objects in a place that curious 
> programmers can easily stumble on. Anything we want to say needs to go in 
> JLS/JVMS (or perhaps the java.lang.Object javadoc).
>
> - Compatibility: pretty clear win here. No interface injection means tools 
> that depend on reflection results won't be broken. (We've found a significant 
> number of these problems in our own code/tests, FWIW.) No new static types 
> means inference results won't change. There's less risk of incompatibilities 
> when adding/removing the 'identity' and 'value' keywords (although there can 
> still be source, binary, and behavioral incompatibilities).
>

--Dan

Reply via email to