Forward references in initializers

John Rose john.r.rose at oracle.com
Thu Nov 7 21:27:48 UTC 2024


Thank you; I prefer going to simplest possible ordering rules,
if I understand this question.  (It’s possible I’m missing a point.)

I think the simplest rule is the direct conjunction of two
independent rules: (a) do not make backwards textual references
among initializers, and (b) enforce the new DA rules when those
initializers are folded into the constructor.

IIUC some “more expressive” rules can attempt to split the set
of non-static fields into two “buckets”, strict and non-strict,
and enforce textual ordering rules only within one “bucket”.

Note also that static fields would also need to be split into
two buckets in a parallel way.  In fact, the ordering rules
already (pre-Valhalla) apply to two buckets: non-static and
static.  The “more expressive” rules give us four buckets.
I found it hard enough to learn to navigate the two-bucket
restrictions, as a young Java programmer.  Four buckets
would have been a steeper hurdle to get across.

One other observation:  Field initializers are much more
useful for statics than for non-statics, since one field
init doesn’t always map cleanly to many non-static field
instances, but it does usually map cleanly to a unique
static field instance.  Thus, adding complexity to gain
expressiveness mainly affects statics; the complexity
will be there but not beneficial to non-static fields.
And even then, the extra expressiveness of being able
to write your static (or non-static) fields in more
orders (not all orders, just “more” orders) is not a
very big gift to programmers.

All Java programmers have learned to sort their fields
in response to occasional snarking from javac.  Whether
there are two or four buckets, they will continue to
do so.  The four buckets would be perceived as excess
fussiness with little upside, I think.

HTH

On 7 Nov 2024, at 12:36, Dan Smith wrote:

> I've been looking with Vicente and Ella at the rules for forward 
> references in field/block initializers. I originally specified it in 
> the JEP 401 language spec to maximize expressiveness, but I'm now 
> thinking we'd be better off sticking with the current left-to-right 
> treatment.
>
> Here's a test:
>
> value class ValueTest {
>     { System.out.println(x); }
>     int x = "abc".length();
> }
>
> The JEP 401 spec rules say this is allowed, because 'x' has an early 
> initializer, and the block executes late. That is, the <init> method 
> looks like:
>
> x = "abc".length();
> super();
> { System.out.println(x); }
>
> This could also manifest with null-restricted types:
>
> class NullTest {
>     int x = y.length();
>     String! y = "abc".substring(1);
> }
>
> Which might compile to:
>
> y = "abc".substring(1);
> super();
> x = y.length();
>
> Note that we could actually do something similar with constant fields 
> today, because constant fields are initialized before anything else:
>
> class StaticTest {
>     static int x = y.length();
>     static final String y = "abc";
> }
>
> But we don't: the rule simply says that forward references are 
> illegal, regardless of the timing of initialization at run time.
>
> Reflecting on this, I think all of ValueTest, NullTest, and StaticTest 
> should be errors.
>
> I like that, under the existing left-to-right rule, a reader can make 
> sense of the initialization code, *as if* it were all run at once, 
> left to right. In the rare cases that timing/side effects matter, a 
> more sophisticated reader would need to understand that some 
> initializers run early, and others run late. But because of the 
> restrictions on early construction code (no field reads), we can leave 
> the left-to-right reading as "good enough" for most developers, and 
> stick with language rules that reinforce this.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-experts/attachments/20241107/c7d0fa88/attachment-0001.htm>


More information about the valhalla-spec-experts mailing list