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