Summary
-------
Allow statements to appear in constructors before `this()` or `super()` call.
Problem
-------
The Java language disallows statements in constructors prior to `this()`/`super()` as a way of preventing access to the current instance prior to superclass construction. This ensures that object construction proceeds in an orderly fashion "from the top down".
However, this rule prevents a variety of common patterns that are available to regular methods. For example:
* "Fail fast" validation of constructor parameters as the first order of business
* Creating an object to pass to the superclass constructor in two different parameter positions
* Complex preparation and/or selection of superclass constructor parameters
This rule is more restrictive than it needs to be. All of the existing semantic and safety guarantees relating to constructors are still preserved if code can appear prior to `this()`/`super()` as long as two criteria are met:
* The code does not refer to the current `this` instance (either explicitly or implicitly)
* There are no `return` statements
Note that the first item is not new; it is exactly the same criterion that applies today to expressions within a `this()`/`super()` call.
Solution
--------
Change the grammar for constructors containing an explicit `this()`/`super()` call from:
```
ConstructorBody:
{ [ExplicitConstructorInvocation] [BlockStatements] } ;
```
to:
```
ConstructorBody:
{ [BlockStatements] } ;
{ [BlockStatements] ExplicitConstructorInvocation [BlockStatements] } ;
```
Also, correct an error in the JLS, which currently defines the inside of a `this()`/`super()` call as a _static context_. This is inconsistent with long-standing practice by both developers and the compiler.
For example, code inside inner class constructor `this()`/`super()` statements commonly refer to the outer instance, as in this example:
```
public class MyClass {
public void doSomething() {
// ...
}
public class MyThread extends Thread {
public MyThread() {
super(MyClass.this::doSomething);
}
}
}
```
Instead, we redefine the inside of a `this()`/`super()` call and any prior statements as a _pre-construction_ context, and clarify the distinction:
* A _static context_ is one in which there is no `this` instance defined, so (for example) references to `this`, generic type parameters or outer instances make no sense.
* A _pre-construction context_ is one in which there is a `this` instance but it may not be referenced because it is uninitialized.
On amber-dev there was a good deal of discussion regarding the how far to expand the rules. The eventual consensus was to take a conservative approach, so the above set of changes represents a minimal choice. The further options that were considered are:
* Allow multiple `this()`/`super()` calls, and use DA/DU analysis to ensure exactly one call is ever executed
* Allow assignments to instance fields prior to `this()`/`super()` to facilitate working around "`this` escapes"
* Allow `this()`/`super()` within `try { }` blocks, with the requirement that if any exceptions are caught the constructor must complete abruptly.
As a side note, all but the last of these options are compatible with the existing JVMS; the last one would require a (straightforward) change.
It should also be noted that there is no change to the semantics of existing programs.
Specification
-------------
Summary of JLS modifications:
* Update the grammar to allow statements (other than `return`) to appear prior to `super()` or `this()`.
* Define the statements up to and including a `super()` or `this()` call as a "pre-construction context".
* Narrow the definition of "static context" to exclude pre-construction contexts.
* Update restrictions on static contexts to also restrict pre-construction contexts where appropriate.
There are no explicit specification changes for record and enum classes; constructors in these classes inherit the new rules in the natural way:
* Enum constructors and non-canonical record constructors may invoke `this()` but not `super()`; as a result, these constructors may now contain statements before `this()`.
* Canonical record constructors are not allowed to explicitly either invoke `super()` or `this()`, so there is no effect on them.
See the attached ZIP file for precise details.
Notes
-----------------
Discussion on amber-dev (these are all one thread):
* https://mail.openjdk.org/pipermail/amber-dev/2023-January/007680.html
* https://mail.openjdk.org/pipermail/amber-dev/2022-October/007537.html
* https://mail.openjdk.org/pipermail/amber-dev/2022-November/007540.html
* https://mail.openjdk.org/pipermail/amber-dev/2022-December/007627.html
Discussion on compiler-dev:
* https://mail.openjdk.org/pipermail/compiler-dev/2023-February/021960.html
There is also [a prototype implementation in the Amber repository](https://github.com/openjdk/amber/tree/super-init).