> On Nov 9, 2024, at 2:59 PM, John Rose <john.r.r...@oracle.com> wrote:
> 
> Boiling it down:  Classify init actions (field initializers
> or instance initializers) as pre-super or post-super; only
> strict field initializers are pre-super.  Then, require that
> a post-super init action must never precede (in left to right
> order) a pre-super init action (i.e., a strict field init).
> 
> That would remove one kind of paradoxical appearance of
> disorder.  Is it worth it?  Maybe.

Eh, I'm open to it, but it seems kind of counter-productive—sure, a class that 
follows this rule avoids the tiny risk of surprising sequencing behavior, 
possibly improving readability (if they happen to do some other odd things); 
but it does it by forcing all authors to think/care about the sequencing in 
order to satisfy the rules. I'd rather most programmers just not think about 
it, and in the rare case that a problem occurs, the compiler can guide them.

> On Nov 11, 2024, at 4:05 AM, Maurizio Cimadamore 
> <maurizio.cimadam...@oracle.com> wrote:
> 
> The main point here is that whether strict fields are initialized 
> before/after a super call is a very low-level detail that we'd like most 
> developers to happily ignore. But if the distinction surfaces up at the level 
> of DA/DU and field assignment, this is no longer strictly true, and it is 
> possible that some developers might be puzzled as a result, and have to dig 
> much deeper than they'd comfortable with to find exactly why that is the 
> case. Preserving the illusion that all fields are created equal seems kind of 
> nice, even though it is still an illusion.

Ok, but see my next message. :-) In order to use DA/DU to enforce requirements 
about initialization before 'this()'/'super()' calls, we need DA/DU to model 
the actual state of the variables at that point, not a simplified version that 
pretends all initializers run at once.

Where that leaves me is: even though it's a little surprising, the DA/DU 
anomaly I raised is not the end of the world, and the cure seems worse than the 
disease. Left-to-right is a reasonable approximation of what happens most of 
the time, but DA/DU needs to be a little more nuanced.

Note that for this anomaly to come up, we need two very cornery feature usages: 
(1) an instance initializer block (or, perhaps, some feature that introduces 
mixed early/late field initializers); (2) an assignment to a field within 
another field's initializer. Combine these two little-used features, and you 
get an initially-surprising but logical result. <shrug> If you don't like it, 
don't write your code that way.

> On Nov 11, 2024, at 4:54 AM, Brian Goetz <brian.go...@oracle.com> wrote:
> 
> I will reiterate my point that I think changing these rules is something that 
> is more amenable to a strict class, then to a subset of the fields being 
> strict. I continue to think that we are missing an abstraction here.


The source of complexity that you'd like to eliminate is this: some classes can 
have both early and late initializer code. In value classes, that manifests as 
an (early) field initializer plus a (late) initializer block. In uses of '!', 
that could manifest as mixed '!' and non-'!' fields (depending on how we handle 
this situation). Given a strictly-initialized-by-default class feature, it 
could also come up if there were a "but treat this one as late" opt-out.

To get to the happier space you're envisioning, we'd need two things:

- If any field initializers run early, all field initializers run early. With 
an appropriate class-level opt-in, this doesn't seem so bad. Corner-case 
must-be-late code can always be put in a constructor. I'm not sure where it 
leaves '!' types though.

- If there's any early initialization, initializer blocks also run early. But 
what's the point of an initializer block that can't touch 'this'? Maybe 
nothing, and we outlaw them in value/strict/whatever classes. Or maybe we 
support field reads during early construction (as we've discussed elsewhere), 
and I bet that would address most of the use cases for an initializer block.

I'd like to explore this further in some corpus code, but I kind of think 
getting past the field read limitation would go a long way to making 
strict-by-default everywhere viable (with, somehow, a minimal opt in for 
compatibility, giving authors a chance to specially handle things like cycles).

> On Nov 11, 2024, at 6:02 AM, Maurizio Cimadamore 
> <maurizio.cimadam...@oracle.com> wrote:
> 
> class Test {
> strict int x = 1;
> int y = x; // ok
> int z = 2;
> strict w = z; // error
> }
> 
> Field initialization order is already fairly complex as it is (I mean 
> remembering where a field initializer is effectively expanded into by the 
> compiler). Adding new rules in this area is going to increase complexity.


Under the "status quo" rules that I'm defending, the error message here is 
straightforward: you can't reference 'z' in an early construction context. No 
need to worry about DA/DU.

That's the magic that lets us treat early execution almost as an optimization: 
your code doesn't have any dependency on 'this', so what difference does 
execution timing make to you, relative to the state of 'this'? ("Almost an 
optimization", because there's always the tiny risk that the initializer code 
depends on some external state for which sequencing is important.)

I'll note, though, that if we allow field reads in an early construction 
context, this whole story changes and we'll definitely need to guarantee 
left-to-right execution.

Reply via email to