JDK-8300786 - No longer require super() and this() to appear first in a constructor

Archie Cobbs archie.cobbs at gmail.com
Wed Feb 8 17:56:08 UTC 2023

On Tue, Feb 7, 2023 at 4:48 PM Archie Cobbs <archie.cobbs at gmail.com> wrote:

> FWIW in the JEP I've raised the importance of fixing this bug in the spec
> <https://bugs.openjdk.org/browse/JDK-8301649> (i.e., that constructor
> invocation is not really a "static context" but truly something different -
> what we're calling a "pre-initialization context") and made it one of the
> "goals" of the JEP, because the gulf between the spec on one hand and the
> compiler's current behavior (and what everyone has actually been doing for
> the past decade) on the other hand is pretty glaring.


Along these lines, I've added this new section to the "Motivation" section:

(Also, presumably people who are interested in following the JEP can
'watch' it, so I won't post any more such updates after this one.)

Fixing a Specification Bug
> JLS §8.1.3 defines *static context* and notes that "The purpose of a
> static context is to demarcate code that must not refer explicitly or
> implicitly to the current instance of the class whose declaration lexically
> encloses the static context". Going by its stated purpose, a static context
> would seem to naturally apply to code inside a super() or this()
> invocation, and in fact the JLS does just that. Prior to the advent of
> generics, inner classes, and captured free variables, this yielded the
> correct semantics for superclass construtor invocation.
> However, as §8.1.3 notes a static context prohibits:
>    - this expressions (both unqualified and qualified)
>    - Unqualified references to instance variables of any lexically
>    enclosing class or interface declaration
>    - References to type parameters, local variables, formal parameters,
>    and exception parameters declared by methods or constructors of any
>    lexically enclosing class or interface declaration that is outside the
>    immediately enclosing class or interface
> Those rules make the following program illegal:
> import java.util.concurrent.atomic.AtomicReference;
> public class ClassA<T> extends AtomicReference<T> {
>     private int intval;
>     public ClassA(T obj) {
>         super(obj);
>     }
>     public class ClassB extends ClassA<T> {
>         public ClassB() {
>             super((T)null);             // illegal - 'T'
>         }
>     }
>     public class ClassC extends ClassA<Object> {
>         ClassC() {
>             super(ClassA.this);         // illegal - 'this'
>         }
>     }
>     public class ClassD extends ClassA<Integer> {
>         ClassD() {
>             super(intval);              // illegal - 'intval'
>         }
>     }
>     public static Object method(int x) {
>         class ClassE extends ClassA<Float> {
>             ClassE() {
>                 super((float)x);        // illegal - 'x'
>             }
>         }
>         return new ClassE();
>     }
> }
> But not only has this program compiled successfully since at least Java 8,
> the above idioms are in common use. The mental model that the compiler and
> developers seem to both be using is indeed that code "must not refer
> explicitly or implicitly to the current instance of the class whose
> declaration lexically encloses" the code in question. However, this is no
> longer what a "static context" prohibits; instead, it goes beyond that, for
> example, restricting even references to generic type parameters.
> The underlying issue is that "static context" is applied to two scenarios
> which are similar, but not equivalent:
>    1. When there is no 'this' instance defined, e.g., within a static
>    method
>    2. When the 'this' instance is defined but must not be referened,
>    e.g., prior to superclass initialization
> The current definition of "static context" is appropriate for scenario #1,
> but after the addition of generics, inner classes, and captured free
> variables to the language, no longer for scenario #2. We need a new,
> distinct concept; let's call it a "pre-initialization context". The rules
> for a "pre-initialization context" should align with developers' current
> mental models (and compiler behavior) for what's allowed prior to
> superclass initialization. Once defined, the rules for a
> "pre-initialization context" can then extend to statements prior to
> superclass initialization, and for the same reason.


Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20230208/436ad739/attachment.htm>

More information about the amber-spec-experts mailing list