Draft Spec for Flexible Constructor Bodies (JEP 513)
forax at univ-mlv.fr
forax at univ-mlv.fr
Tue Apr 29 16:13:18 UTC 2025
----- Original Message -----
> From: "daniel smith" <daniel.smith at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Stephan Herrmann" <stephan.herrmann at berlin.de>, "amber-spec-experts" <amber-spec-experts at openjdk.org>
> Sent: Monday, April 28, 2025 10:01:06 PM
> Subject: Re: Draft Spec for Flexible Constructor Bodies (JEP 513)
>> On Apr 24, 2025, at 6:34 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>>
>>> Perhaps we should be asking: who will emit the ACC_STRICT_INIT flag, and when?
>>
>> yes, making the early field initialization part of FCB muddy our chances to
>> later uses early initialization as a signal for the compiler to declare the
>> field as ACC_STRICT_INIT.
>
>> So i would prefer to have a real plan on how Java will use ACC_STRICT_INIT. For
>> now, we have not ruled out to use early initialization as a signal, so i would
>> like to keep that option open, even if that means going back to the original
>> proposal of FCB, and only releasing that.
>
> Let me clarify how we've been thinking in recent Valhalla work about the path
> toward an eventual strict-by-default world in the language:
>
> 1) With value classes, we introduce the concept of strictly-initialized fields
> in the JVM, enforce rules that value class sources require early initialization
> of their fields, and provide an "early-by-default" interpretation of these
> classes (early instance field initializers, implicit 'super()' at the end of
> constructors). Potentially, we can also subject record classes to these
> behaviors, with some small compatibility risk. [See
> https://openjdk.org/jeps/401#Value-object-initialization]
>
> 2) At the same time, we introduce some *warnings* to encourage a style of
> programming in identity classes that could support early-by-default compilation
> in the future. [See
> https://openjdk.org/jeps/401#Encouraging-early-initialization-of-identity-classes]
>
> 3) At some later point, we provide a language feature (mechanism TBD) to allow
> identity classes to opt in to the value class early-by-default rules. In a
> class that opts in, a field that is early-initialized is treated as
> ACC_STRICT_INIT, and a field that is late-initialized is not. (It might be an
> error or warning to try to mix initialization timings of a single field.)
>
> Where does support for early assignment in constructor bodies fit in? It's a
> hard prerequisite to (1), because that is the only way to initialize a value
> class field. It's also important for (2), because one way to address warnings
> about 'this' dependencies is to add a 'super()' call to the constructor, and
> then put the 'this'-dependent code after that call (but keep the rest of the
> code early).
>
> Note that (2) has no semantic impact, so it's something we can readily impose on
> every class. And then the idea is that (3) allows programmers to opt in to
> subtly different semantics (like the memory model effects you've illustrated);
> a program that has addressed the warnings by then won't need to make any
> additional source changes.
>
> Of course this is not the only possible way to approach the problem, but there
> are some good reasons to arrange things like this:
>
> - (1) comes with early initialization requirements, but we don't want to tie the
> semantic changes of (3) to getting value classes out the door. Frankly, (3) is
> a can of worms and I'm not sure where it will lead. So there needs to be some
> space between (1) and (3).
>
> - (1) encourages class authors to think about construction timing and 'this'
> dependencies, and so it's a good opportunity to get them to consider those
> things throughout their code—hence tying (1) and (2) together.
>
> (One piece of this that isn't clear to me, and that we need to discuss further,
> is where '!'-typed fields fit in—they also require early initialization and
> ACC_STRICT_INIT. Maybe using '!' on a field is one form of the opt-in described
> in (3). Or maybe that's too indirect. TBD...)
Hello Dan,
thanks for taking the time to reply.
The problem of (2), is that if you emit a warning, people will want to change the code but they need (3) for that.
Let me go from the other direction, with SF, we have a very potent feature,
a code that for example starts a thread in the constructor is now valid, something I never though it was possible.
public class Foo {
private final String s;
public Foo() {
this.s = s;
super(); // memory freeze
new Thread(() -> /* use this.s here */).start();
}
}
But this feature requires to change the VM to add a memory barrier for Object.<init>() *and* be sure that those changes have no negative impact on performance.
Because of the perf part, there is a non-zero chance that this feature never exists.
For value type, we currently allow early initialization of fields with two restrictions:
- all fields must be final
- the call to super() has to be the last call of the constructor.
With those restrictions the VM does not have to be changed because the memory freeze due to the final fields is done at the same time as the call to super() (at the end of the constructor).
Now, you want to add a warning for helping people to move to a world with early initialization of fields, FCM has to support early field initializations.
So for me, FCM has to have the same restrictions has for value types, all early initialized fields have to be final, the call to super has to be the last call to the constructor.
And then later, if the VM changes are okay, we can revisit those restrictions.
Rémi
As a side note, '!' is STRICT_INIT_FIELD + nullcheck, so the field has to be initialized before the super call, we can keep the constraint that super() has to be the last statement but given that the field can be "not final", we need at least the VM to insert a memory freeze at the end of the constructor (like with final).
More information about the amber-spec-observers
mailing list