JDK-8302041 : Permit additional statements before this/super in constructors
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 22
  • Submitted: 2023-02-08
  • Updated: 2023-10-20
  • Resolved: 2023-10-20
Related Reports
CSR :  
Relates :  
Description
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).
Comments
Moving amended request to Approved.
20-10-2023

[~darcy] Moved back to draft, attached revised spec. The JEP has been extensively rewritten also.
09-10-2023

Thanks for the clarification [~acobbs]; moving to Approved.
15-08-2023

[~darcy] Spec all good - I wrote it :-)
30-07-2023

[~gbierman], please review the specification changes.
28-07-2023

Added a description of how enum and record classes are affected.
28-07-2023

Moving to Provisional, not Approved. Are any updates needed to JLS 8.9.2. Enum Body Declarations? There are various special cases for constructors there. If no special handling is needed the CSR (and possibly JEP) should state that explicitly.
28-07-2023

Looks like discussion on amber-spec-experts has quieted down - no more comments after the latest draft spec changes for > 2 weeks: https://mail.openjdk.org/pipermail/amber-spec-experts/2023-June/003878.html I've removed the obsolete inline spec changes from the CSR and attached Gavin's latest draft spec changes in HTML to this CSR as a ZIP file to sync things up. Moving back to finalized.
10-07-2023

I see the more formal version of the proposed changes are out for discussion on amber-dev: https://mail.openjdk.org/pipermail/amber-dev/2023-April/008036.html Administratively, moving this request to Provisional; please re-Finalize once the more formal spec is ready.
24-04-2023

Thanks Joe. I've inlined the proposed JLS changes into this CSR and will re-finalize. Happy to adjust further if needed though.
21-03-2023

Moving back to Provisional. [~acobbs] and [~vromero], as the CSR also serves an archival purpose, some stand-alone representation of the specific specification change needs to be included as part of the CSR. This can be done in-line or or as an attachment, etc.; links to external sites can be used as a convenient supplement. This is to say "see the JEP" isn't sufficient here since the JEP can be changed subsequently and thus not reflect what was approved in the CSR. If you want to re-Finalize this CSR now, you can included the specific specification changes (or wait for JDK-8303093). HTH
21-03-2023

Thanks Joe. I've moved this one to Finalized.
17-03-2023

[~vromero], you or [~acobbs] are free to Finalize the CSR for the second phase of review ahead of any state changes in the JEP. The people working on CSR are responsible for advancing it from Provisional. (A JEP should be in at least Provisional state before it goes PTT.) HTH
17-03-2023

[~darcy] is this CSR in provisional state until the JEP is targeted or is there any thing (action) missing on our side? Thanks!
17-03-2023

Moving to Provisional, not Approved.
02-03-2023