On Wed, Feb 23, 2022 at 1:36 PM Dan Smith <daniel.sm...@oracle.com> wrote:
>
> Fred suggested that we enumerate the whole space here. So, some cases to 
> consider:
>
> { ACC_PERMITS_VALUE, not }
> { has an <init> declaration, not }
> { implements IdentityObject, not }
> { implements ValueObject, not }
>
> "implements" here refers to both direct and indirect superinterfaces.
>
> I'll focus on the first two, which affect the inference of superinterfaces.
>
> (1) ACC_PERMITS_VALUE, <init> declaration
>
> This is a class that is able to support both identity and value subclasses. 
> It implements no extra interfaces, but can restrict its subclasses via 
> 'implements IdentityObject' or 'implements ValueObject'.
>
> (2) ACC_PERMITS_VALUE, no <init> declaration
>
> The JVM infers that this class implements ValueObject, if it doesn't already. 
> If it also implements IdentityObject, an error occurs at class load time.
>
> (Design alternative: we could ignore the <init> declarations and treat this 
> like case (1). In that case, the class could implement IdentityObject or be 
> extended by identity classes without error (as long as it doesn't also 
> implement ValueObject). But those identity subclasses couldn't declare 
> verification-compatible <init> methods, just like subclasses of abstract 
> classes that have no <init> methods today.)

I think ignoring the <init> declarations is the model we want here.
Both (1) and (2) should be treated the same by the VM - in either case
the subclasses can implement IdentityObject or ValueObject.  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).

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

An abstract class that doesn't have the ACC_PERMITS_VALUE flag binds
tightly to the IdentityObject interface.  The presence of the
ACC_PERMITS_VALUE flag delays the interface binding until we hit
either a concrete class or an abstract class without the flag.

>
> (4) no ACC_PERMITS_VALUE, no <init> declaration
>
> This is a class that effectively supports *no* subclasses. We don't infer any 
> superinterfaces, but it can choose to implement IdentityObject or 
> ValueObject. A value class that extends this class will fail to load.

See above.  No ACC_PERMITS_VALUE flag means it binds tightly to
IdentityObject and can only be subclassed by IdentityObject-compatible
classes.  All value classes extending this abstract will fail to load.

> If the class doesn't implement ValueObject, an identity class that extends 
> this class could load, but couldn't declare verification-compatible <init> 
> methods, just like subclasses of abstract classes that have no <init> methods 
> today.

The class extending this will load but cannot be instantiated.
Verification succeeds but resolution of any super() calls in the
constructor will fail to resolve.

>
> (Design alternative: we could ignore the <init> declarations and treat this 
> like case (3). In that case, it would be an error for the class to implement 
> ValueObject, because it also implicitly implements IdentityObject.)

+1.

>
> ---
>
> Spelling this out makes me feel like treating the presence of <init> methods 
> as an inference signal may be overreaching and overcomplicating things. 
> Today, declaring an <init> method, or not, has no direct impact on anything, 
> other than the side-effect that you can't write verification-compatible 
> <init> methods in your subclasses. I like the parallel between "permits 
> identity (via <init>)" and "permits value (via flag)", but flags and <init> 
> methods aren't really parallel constructs; in cases (2) and (4), we still 
> "permit" identity subclasses, even if they're pretty useless.
>
> (And it doesn't help that javac doesn't give you any way to create these 
> <init>-free classes, so in practice they certainly don't have parallel 
> prevalence.)
>
> Pursuing the "design alternative" strategies would essentially collapse this 
> down to two cases: (1) ACC_PERMITS_VALUE, no superinterfaces inferred, but 
> various checks performed (e.g., no instance fields); and (3) no 
> ACC_PERMITS_VALUE, IdentityObject is inferred, error if there's also an 
> explicit 'implements ValueObject'.
>
> How do we feel about that?
>

I think this design alternative is the right strategy and more inline
with existing conventions for how the VM handles classes.

--Dan

Reply via email to