TLDR: I'm convinced, let's revise our approach so that the JVM never infers 
interfaces for abstract classes.

On Feb 24, 2022, at 8:57 AM, Dan Heidinga 
<heidi...@redhat.com<mailto:heidi...@redhat.com>> wrote:

Whether
they can be instantiated is a decision better left to other parts of
the spec (in this case, I believe verification will succeed and
resolution of the `super()` <init> call will fail).

Right, my mistake. Verifier doesn't care what methods are declared in the 
superclass, but resolution of the invokespecial will fail.

(3) no ACC_PERMITS_VALUE, <init> declaration

The JVM infers that this class implements IdentityObject, if it doesn't 
already. If it also implements ValueObject, an error occurs at class load time.

I think this should be driven purely by the presence of the
ACC_PERMITS_VALUE flag and the VM shouldn't be looking at the <init>
methods.

Sounds like the consensus, agreed.

 The JVM shouldn't infer either IdentityObject or ValueObject
for this abstract class - any inference decision should be delayed to
the subclasses that extend this abstract class.

My initial reaction was that, no, we really do want IdentityObject here, 
because it's useful to be able to assign an abstract class type to 
IdentityObject.

But: for new classes, the compiler will have an opportunity to be explicit. 
It's mostly a question of how we handle legacy classes. And there, it would 
actually be bad to infer IdentityObject, when in most cases the class will get 
permits_value when it is recompiled. Probably best to avoid a scenario like:

- Compile against legacy API, assign library.AbstractBanana to IdentityObject 
in your code
- Upgrade to newer version of the API, assignment from library.AbstractBanana 
to IdentityObject is an error

So, okay, let's say we limit JVM inference to concrete classes. And javac will 
infer/generate 'implements IdentityObject' if it decides an abstract class 
can't be permits_value.

What about separate compilation? javac's behavior might be something like: 1) 
look for fields, 'synchronized', etc. in the class declaration, and if any are 
present, add 'implements IdentityObject' (if it's not already there); 2) if the 
superclass is permits_value and this class doesn't extend IdentityObject 
(directly or indirectly), set permits_value. (1) is a local decision, while (2) 
depends on multiple classes, so can be disrupted by separate compilation. But, 
thinking through the scenarios here... I'm pretty comfortable saying that an 
abstract class that is neither permits_value nor a subclass of IdentityObject 
is in an unstable state, and, like the legacy case, it's probably better if 
programmers *don't* write code assuming they can assign to IdentityObject.

Reply via email to