<div dir="ltr"><div dir="ltr">On Tue, Feb 7, 2023 at 4:48 PM Archie Cobbs <<a href="mailto:archie.cobbs@gmail.com">archie.cobbs@gmail.com</a>> wrote:</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>FWIW in the JEP I've raised the importance of fixing this <a href="https://bugs.openjdk.org/browse/JDK-8301649" target="_blank">bug in the spec</a> (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.</div></blockquote><div><br></div><div>FYI,</div><div><br></div><div>Along these lines, I've added this new section to the "Motivation" section:</div><div><br></div><div>(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.)</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><font size="4">Fixing a Specification Bug
</font><p>JLS §8.1.3 defines <em>static context</em> 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
<code class="gmail-prettyprint">super()</code> or <code class="gmail-prettyprint">this()</code>
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.</p>
<p>However, as §8.1.3 notes a static context prohibits:</p>
<ul><li><code class="gmail-prettyprint">this</code> expressions (both unqualified and qualified)</li><li>Unqualified references to instance variables of any lexically enclosing class or interface declaration</li><li>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</li></ul>
<p>Those rules make the following program illegal:</p>
<pre class="gmail-prettyprint" style="margin-left:40px"><code>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();
}
}</code></pre>
<p>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.</p>
<p>The underlying issue is that "static context" is applied to two scenarios which are similar, but not equivalent:</p>
<ol><li>When there is no 'this' instance defined, e.g., within a static method</li><li>When the 'this' instance is defined but must not be referened, e.g., prior to superclass initialization</li></ol>
<p>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.</p></div></blockquote><br></div>-Archie<br clear="all"><div><br>-- <br><div dir="ltr" class="gmail_signature">Archie L. Cobbs<br></div></div></div>