RFR: 8194743: Compiler implementation for Statements before super() [v14]
Archie Cobbs
acobbs at openjdk.org
Sat Sep 23 15:19:12 UTC 2023
On Sat, 23 Sep 2023 06:57:30 GMT, Chen Liang <liach at openjdk.org> wrote:
> I understand what you mean, since you've clarified long ago. Instead, I mean this from JEP 401:
>
> > Local and anonymous classes may be declared, but (as in a static context) they have no enclosing instance.
>
> Currently local classes declared in pre-construction context have an enclosing instance, and I wonder if we can make them not require enclosing instances like in a static context. Local classes declared after the super/this delegate constructor call in source code will still have an enclosing instance.
The problem is that this is not how the compiler currently behaves.
Consider this class:
public class Test {
public Test(int x) {
}
public Test() {
this(switch (0) {
default -> {
class Local {
}
yield 0;
}
});
}
}
According to JLS 21 §15.9.2, class `Local` does not have an enclosing instance.
Yet here is what's actually emitted by the compiler:
$ javap -classpath classes -c Test$1Local
Compiled from "Test.java"
class Test$1Local {
final Test this$0;
Test$1Local(Test);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:LTest;
5: aload_0
6: invokespecial #7 // Method java/lang/Object."<init>":()V
9: return
}
An explicit goal of JEP 447 is **any existing program must compile to the same bytecode**. So if we adhere to that goal, local classes declared in pre-construction contexts must have outer instances.
I think this is the most natural behavior anyway. Anonymous classes, with their "immediate enclosing instance with respect to superclass S", and their declare-and-instantiate-all-at-once property, are the oddballs. It's appropriate for them to have a special rule where their implicit outer instance "disappears" in a pre-construction context because it would never be possible to provide one.
So my suggestion is to alter this wording in JEP 401:
> Local and anonymous classes may be declared, but (as in a static context) they have no enclosing instance. Inner classes may refer to enclosing instances or captured enclosing variables from their own regulated constructors without error.
>
> These rules coincide with the restrictions imposed in a pre-construction context, as described by [JEP 447](https://openjdk.org/jeps/447), except that they allow for writes to instance fields.
To this:
> Local classes may be declared, but since they require an enclosing instance, they can't be instantiated. Anonymous classes may be declared, but (as in a static context) they have no enclosing instance. Inner classes may refer to enclosing instances or captured enclosing variables from their own regulated constructors without error.
>
> These rules coincide with the restrictions imposed in a pre-construction context, as described by [JEP 447](https://openjdk.org/jeps/447), except that they allow for writes to instance fields.
Also:
> I think there are already similar rules implemented for anonymous classes before this JEP, where the anonymous `Cat$1` (printing "Running") does not require an implicit `Cat` for its constructor while `Cat$2` (printing "Meow") does after compilation:
As remarked above, anonymous classes are different. It's not possible to declare them in one place and instantiate them in another place, so they indeed will not have enclosing instances when declared in a pre-construction context but will have them otherwise, and this behavior is not changing.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/13656#issuecomment-1732340240
More information about the compiler-dev
mailing list