On Nov 22, 2021, at 5:13 PM, Dan Smith <daniel.sm...@oracle.com> wrote: > >> On Nov 22, 2021, at 2:07 PM, Kevin Bourrillion <kev...@google.com> wrote: >> >>> On Mon, Nov 22, 2021 at 6:27 AM Dan Heidinga <heidi...@redhat.com> wrote: >>> >>> I'll echo Brian's comment that I'd like to understand Kevin's use >>> cases better to see if there's something we're missing in the design / >>> a major use case that isn't being addressed that will cause useer >>> confusion / pain. >>> >> Sorry if I threw another wrench here! >> >> What I'm raising is only the wish that users can reasonably default to >> B2-over-B1 unless their use case requires something on our list of "only B1 >> does this". And that list can be however long it needs to be, just hopefully >> no longer. That's probably how we were looking at it already. > > Here's the current list, FYI (derived from JEP 401): > > • Implicitly final class, cannot be extended.
JVMS requires ACC_FINAL on class. > • All instance fields are implicitly final, so must be assigned exactly > once by constructors or initializers, and cannot be assigned outside of a > constructor or initializer. JVMS requires ACC_FINAL on every instance field. (Static fields OK.) > • The class does not implement—directly or indirectly—IdentityObject. > This implies that the superclass is either Object or a stateless abstract > class. JVMS requires a check for this. > • No constructor makes a super constructor call. Instance creation will > occur without executing any superclass initialization code. JVMS rules for invokespecial <init> must exclude this. > • No instance methods are declared synchronized. JVMS forbits ACC_SYNC. on all instance methods. (Static methods OK.) > • (Possibly) The class does not implement Cloneable or declare a > clone()method. > • (Possibly) The class does not declare a finalize() method. A conservative move is to forbid these things, in language and JVMS. Minor precedent: record has similar special cases (for component names). > • (Possibly) The constructor does not make use of this except to set > the fields in the constructor body, or perhaps after all fields are > definitely assigned. JVMS doesn’t care about this. The private opcodes initialvalue and withfield work to set up ’this’ as the constructor executes. It’s OK to sample the value at any time, but maybe the language says, “don’t do that”. I think there are use cases for private methods to work on partially initialized stuff. The theory is tricky. OK to be conservative now and more lenient later. > > And elaborating on IdentityObject & stateless abstract classes: > > An abstract class can be declared to implement either IdentityObject or > ValueObject; or, if it declares a field, an instance initializer, a non-empty > constructor, or a synchronized method, it implicitly implements > IdentityObject (perhaps with a warning). JVMS should enforce corresponding structural rules on loaded classfiles. Neither a source class-or-interface nor a loaded classfile can ever implement both IO and VO at the same time. As a special feature in the JVM I want an explicit form for these “empty constructors”. We’ve discussed this; I’m not sure which form is best, but I don’t want it to be a “not-really-empty” constructor which has a super-call in it; that’s what seemingly “empty” constructor look like today to the JVM. The JVM should both allow and require an empty constructor if and only if the abstract class implements VO. (Alternative: The JVM implicitly injects VO if it sees an empty constructor, and if it sees VO it looks for an empty constructor.) IIRC maybe our last consensus was to add an attribute to an <init> method of signature ()V that says, “whatever you think you see in this method, Mr. VM, please also feel free to skip it.” That’s a more hacky way to specify an empty constructor than would be my preference (which is an ACC_ABSTRACT <init>()V or even a zero-length class attribute). If a VO-only abstract has an <init>()V method, that’s a smell, because it will never be used! OTOH, maybe just being a VO-0nly abstract class is enough to tell the JVM that the constructor is empty, with no further markings. Anyway, there’s a little corner of the design space to consider here. > Otherwise, the abstract class extends neither interface and can be extended > by both kinds of concrete classes. Such a class is very handy. It needs *both kinds of constructors*. Are you thinking that just mentioning the special VO super is enough to trigger inclusion of an empty constructor? That’s probably a good move. Is this the *only* way to request an empty constructor, or is there a way to make an explicit empty constructor? (I mean a really-empty one, not just today’s seemingly-empty ones. Even Object’s empty constructor has an areturn instruction, so it’s not really empty.) > (Such a "both kinds" abstract class has its ACC_PRIM_SUPER—name to be > changed—flag set in the class file, along with an <init> method for identity > classes.) Yes, that makes sense. So maybe a VO-capable abstract class is always assumed to have an implicit empty constructor, even if there is no other marking than the PRIM_SUPER? I guess that’s OK for the JVM. For the source language it might be too magic.