-
Notifications
You must be signed in to change notification settings - Fork 209
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
Allow lazy access to variable in its own initializer. #545
Comments
You could also argue that the enhancement is unnecessary: It introduces a rather complex semantics, it is most likely only going to be helpful in very few situations, and there is a known work-around. So it's not obvious to me that it passes the "carries its own weight" test. |
The workaround has so far been to split If the work-around is so completely regular, why can't we just make that the semantics of the otherwise invalid code? (Without having to write It is just "very few situations". It actually happens quite often when you write asynchronous code with callbacks. |
Would that work for class properties (assuming it prevents const constructors)? class Foo {
late final Future<Foo> foo = _fetchFoo();
} That's a lot better than: class Foo {
Future<Foo> _foo;
Future<Foo> get foo => _foo ??= _fetchFoo();
} |
Yes, a late instance variable initializer can access An eager instance variable initializer is executed during object creation, before the object is completely initialized, so it cannot access |
The idea was discarded in #828. |
Solution to #542.
Proposal
Allow local variable initializers to refer to the variable inside a nested function expression. (There is no need for a top-level access, that will always be an error).
If the variable is
late
, use normallate
variable semantics.If the variable is not
late
, throw on any access happening before the initializer expression has completed.Rationale
Dart does not allow a local variable initializer to refer to the variable.
It also doesn't allow an instance variable initializer to refer to the variable because the initializer expression does not have access to
this
.However, static variables can refer to themselves because they are in the global scope. They are also lazily initialized, and lazy initialization already has semantics for accessing itself during initialization. (Dart 1/2.0 semantics is to throw on cyclic initialization error, NNBD will recurse on the initialization, then throw on the second attempted store if final - it does worry me that we evaluate an initializer expression twice, but you really are asking for it if it happens).
We have defined lazy initialization for
late
local variables, but have not changed the scoping rules, so it's still an error to be self-referential. If we change the scoping rules, you can write;without issues, the semantics are already defined. You then have to read
sub
to force the initialization to happen.Also, with late finals, you can already write:
which is annoying, but avoids the "cannot refer to yourself" without actually improving the safety of anything. (Our definite assignment analysis cannot determine whether
sub
is initialized or not atsub.cancel()
, but usinglate
we turn that into a run-time issue).With that in mind, we can also allow any local variable to refer to itself, with "throw on early access" semantics. It would mean that the variable becomes more expensive, but only for accesses inside the initializer, all other accesses can assume that the variable is initialized.
It is basically equivalent to a rewrite from
... x = ...;
intolate ... x; x = ...;
, which you can do anyway, and definite assignment should recognize that any later access tox
is definitely initialized.So, we would allow something which may fail, but which we already allow by splitting into two lines, and that is what everybody does anyway, so we are not saving anybody from run-time errors, merely making them write more code.
The text was updated successfully, but these errors were encountered: