Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482)
Dan Smith
daniel.smith at oracle.com
Thu May 30 04:39:55 UTC 2024
On May 29, 2024, at 7:57 AM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
On 28/05/2024 18:20, Stephan Herrmann wrote:
* §8.1.3: "An instance of an anonymous class whose declaration occurs in a pre-construction context (8.8.7.1) has no immediately enclosing instance."
To clarify the model: yes, this rule was intentionally removed. It becomes very complicated if you want to make rules about which enclosing instances exist or don't exist based on positioning within a constructor. Example:
class C1 {
C1() {
super();
class C2 { // not early for C1
C2() {
class C3 { // early for C2
C3() {
super();
class C4 { // not early for C3
...
}
}
}
super();
}
}
}
}
Does C4 have a 1st enclosing instance? Yep. 2nd? Maybe no? 3rd? It better...
Instead, the approach we settled on was: early construction contexts have no bearing on whether a class "has" an enclosing instance. It always does, if it's not in a static context.
Meanwhile, there are a bunch of rules about what you can reference from an early construction context *of a particular class*. So, e.g., C4 is in the early construction context of C2, so it is illegal to reference the members of C2 in the body of C4.
(Note that this model has nothing to do with how a compiler translates these classes into bytecode, which enclosing instances get stored in fields, etc. That's a separate problem for javac to deal with.)
Consider the following example:
class Outer {
class Inner {
Inner() {
class Local {
void test() { m(); }
}
new Local().test();
super();
}
}
void m() { }
public static void main(String[] args) {
new Outer().new Inner();
}
}
Here, Local occurs in an early context (used to be pre-constructor, or static). So it has no enclosing instance. But then, how can it refer to Outer::m ?
Revised rules say that Local does not appear in the early construction context *of Outer*, so therefore is allowed to refer to the members of Outer.
In 15.12.1 we say:
If there is an enclosing class or interface declaration of which that method is a member, let E be the innermost such class or interface declaration. The type to search is the type of E.this (§15.8.4).
Ok, so the above program is valid if Outer.this makes sense. But, as per 15.8.4:
The value of a qualified this expression TypeName.this is the n’th lexically enclosing instance of this.
But there’s no enclosing instance for Local, so what does Outer.this evaluates to?
Yep, that's part of what motivated this change. You need to be able to talk about the full chain of enclosing instances of Local, even if some of them are "unusable".
I think this has always been a bit of an issue - we always treated anonymous classes occurring in super calls as “static”, but that doesn’t explain how such classes seem to have access to members of enclosing classes.
Agree, it wasn't well-specified before.
It seems like this area needs a bit of an overhaul? Or am I missing something?
Right. The first step was to recognize that an early construction context is not the same thing as a static context. The next step was to allow enclosing instances for classes in early construction contexts. And the third step was to ensure that the restrictions on references from early construction contexts continue to apply appropriately inside nested classes.
I believe this is now appropriately handled by the spec changes Gavin shared, but it's good to validate that with extra eyeballs.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20240530/f43e12bd/attachment-0001.htm>
More information about the amber-spec-experts
mailing list