SoV-3: constructor questions
Dan Smith
daniel.smith at oracle.com
Wed Jan 26 22:15:12 UTC 2022
> On Jan 26, 2022, at 2:18 PM, Dan Heidinga <heidinga at redhat.com> wrote:
>
> After re-reading the State of Valhalla part 3 again [1], I have a
> couple of questions on constructor handling:
>
> 1) The rules for handling ACC_PERMITS_VALUE are different between
> SoV-2 and SoV-3 in that the language imposes constraints the VM
> doesn't check. Is this deliberate?
>
> SoV-2 says:
>> The classes they can extend are restricted: Object or abstract classes with no fields, empty no-arg constructor bodies, no other constructors, no instance initializers, no synchronized methods, and whose superclasses all meet this same set of conditions. (Number is an example of such a class.)
>
> while SoV-3 says:
>> Perhaps surprisingly, the JVM does not perform the following checks for value-superclass candidates, although the source language compiler will typically do so:
>>
>> It should have declared an empty no-argument constructor. (Or if it didn’t, then the author has somehow consented to having all of the constructors being skipped by the unnamed factory methods of value subclasses.)
>
> "Perhaps surprisingly" is right as I'm surprised =) and not sure I
> follow why the VM wouldn't enforce the restriction. Is it to avoid
> having to specify the attributes of that constructor?
We can come up with a rule to specify, in the Java language, what an "empty constructor" looks like. (Nothing syntactically in the body, for example.)
It's harder for the JVM to specify what an "empty <init> method" looks like. It must at least have an 'invokespecial' of its superclass's <init>. Might do some stacking of arguments. Etc. JVMs don't want to be in the business of recognizing code patterns.
So the model for the JVM is: you can declare <init> methods if you want to support identity subclass creation, and you can declare ACC_PERMITS_VALUE if you want to support value subclass creation. Independent channels, no need for them to interact.
> Which leads me to the next concern: how javac will compile the "empty
> no-arg constructor bodies" required by SoV-2? Or is the answer we
> don't care because the VM won't check anyway?
The Java language will produce class files for qualifying abstract classes with:
- ACC_PERMITS_VALUE set
- The same <init> methods it would have produced in previous versions (involving a super invokespecial call)
For a non-qualifying abstract class, you'll get
- ACC_PERMITS_VALUE *not* set
- The same <init> methods it would have produced in previous versions (potentially involving arbitrary user code)
And, yes, the JVM doesn't care. Other patterns are possible in legal class files (but javac won't produce them).
> 2) What is the rationale behind the return type restrictions on <new> methods?
>
>> A <new> method must return the type of its declaring class, or a supertype.
> ....
>> While <new> methods must always be static and must return a type consistent with their class, they can (unlike <init> methods) be declared in any class file, as far as the JVM is concerned.
>
> If I'm reading this correctly, to enforce the first quote we'll need a
> verifier check to ensure that the declared return type of the <new>
> method is consistent with the current class or a supertype. But
> Object is a common supertype, as is ValueObject, so I'm not sure what
> we're gaining with this restriction as any type is a valid candidate
> for return from a <new> method as anything can be a subclass of
> Object.
Treatment of <new> methods is still unresolved, so this (and the JEP) is just describing one possible approach. I tried to reach a conclusion on this a few months ago on this list, but we ended in an unresolved place. I'll try again...
Anyway, in this incarnation: the rule is that the return type must be a type that includes instances of the current class. So, in class Point, QPoint is okay, LObject is okay, but LString is not.
> We get a better restriction from the `aconst_init` and `withfield`
> bytecodes which "can only be executed within the nest of the class
> that declares the value class being initialized or modified". Do we
> actually need the restriction on the <new> method or should it be
> considered non-normative (aka a best practice)?
I think there are certainly use cases for class instantiation outside of a method named '<new>' (even if javac won't generate them), and wouldn't want to limit those instructions to methods named '<new>'. It gives '<new>' more power than I think we intend—it's supposed to be a convenient place to put stuff, not a mandatory feature of instance creation.
More information about the valhalla-spec-observers
mailing list