(Resending as I forgot to CC the list - Sorry for the duplicate email Dan)

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

Ok.  This is due to a class having a single no-args `<init>()V` method
that has to do double duty - supply the super-call for identity
subclasses and be ignored by value subclasses.  Seems reasonable.

> > 2) What is the rationale behind the return type restrictions on <new> 
> > methods?
....
> 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.

I don't understand the point of this restriction.  Since
Ljava/lang/Object; is acceptable (and has to be), I can use a `<new>`
method to return *any* class but the caller will need to downcast to
use it.

class QPoint {
  static Object <new>() { return new String("string factory"); }
  static void user() {
    String s = (String) QPoint.<new>:()Ljava/lang/Object;
  }
}
We've made the bytecode patterns ugly by requiring a checkcast - and
maybe slightly harder to write a large set of factory methods due to
needing different descriptors for each one - and gained what?  Javac
may not generate this kind of code but it still seems odd to restrict
it.

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

I think we agree here - the useful restrictions are on only allowing
aconst_init / withfield with a Nest.  Given we've already agreed to
that restriction, I'm trying to understand the benefits of further
restrictions on the descriptor for <new>.

--Dan

On Wed, Jan 26, 2022 at 5:15 PM Dan Smith <daniel.sm...@oracle.com> wrote:
>
> > On Jan 26, 2022, at 2:18 PM, Dan Heidinga <heidi...@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.
>

Reply via email to