-
Notifications
You must be signed in to change notification settings - Fork 213
Ordering of augmenting initializers and getters on late variables #3987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@lrhn can you tackle this one? I think you have the best handle on exactly what needs to be specified here. |
I'll try. I may have to invent new terminology in the documentation How do you feel about "declaration" being the syntax and "definition" being what it introduces, as used above? Then a variable declaration introduces 2-3 definitions: a variable definition, a better definition and maybe a setter definition, which the class contains, and augmenting declarations create a new definition from an existing (augmented) definition. For this case, a late variable with an initializer introduces a late variable definition (which is identified by the declaring context and name, but does not itself introduce a public name), and a default getter declaration (and setter if not final). I'll try to write that up formally. (I like that the variable declaration itself gets an entity, separate from the get and setter.) |
I think that sounds pretty good.
...which replaces the previous definition (not quite correct, the previous also exists, but now all references to this definition should refer to the new one).
Agreed. In general I think this makes sense. |
With #4357, this isn't relevant any more. Variables (late or not) can't be augmented. |
A late variable with an initializer expression evaluates the initializer expression when first read and not initialized.
Augmentations allow you to augment both the initializer expression and the getter.
The default getter is the one which evaluates the initializer, but it needs to see the actual initializer of the variable, not the one at the base declaration.
That is most likely not a problem, but it needs to be specified precisely to have the desired behavior.
(That is: We should remember this when writing the specification and tests.)
Example:
Seeing the fully augmented initializer expression is consistent with how we treat other augmenting declarations: An augmenting declaration can only see the augmented definition of the one thing it augments itself, anything else is always the fully augmented property, accessed by name. The difference here is that you can't access the initializer expression "by name", that would denote the getter, but we are treating the late variable getter as being able to access "the variable's initializer expression", which is what it does.
(Object initialization will have to similarly evaluate the fully augmented initializer expression while creating the object, but that doesn't feel as weird because we don't get to augment the code that triggers the initialization, which we do when augmenting the getter of a late/lazy variable.)
In pseudo-terms:
late final String name = "banana";
introduces a getter definition with a synthetic body which does theif (name::initialized) return name::get; return name:set(name::initializer);
operation.augmented
, it invokes that default implementation.name::initializer
which evaluates the initializer expression of the fully augmented variable definition. Even if the default getter was introduced before the final augmenting declaration for the initializer expression.Even more, the behavior of the body of the default getter can be defined based on the properties of the fully augmented variable definition:
Here we could say that the default getter "body"/invocation behavior is defined based on the fully augmented declaration:
Or we can say that the default getter body does that check at runtime (which it obviously doesn't, but then that's an optimization):
final
, throw. Otherwise write the value and return iut.LateInitializationError
.Since the "does it has an initializer expression" is known at compile-time, we will expect all compilers to be smart.
(It's possible to make accessing a late variable never reach its default getter, to do initialization. It's weird, but nothing you couldn't already do by subclassing and overriding the getter.)
The text was updated successfully, but these errors were encountered: