You can declare a late final
variable.
If you declare it with an initializer, late final foo = computeSomething();
, then it is a lazy final variable. You can't assign to the variable, but its value is only computed the first time the variable is read. (In my experience, this is never the right choice for local variables, even though the language allows it. If you care about lazy initialization of a local variable, you also almost always want to know whether it was initialized, and a lazy variable doesn't give you that information. It's also confusing that the code is executed out-of-order, and it doesn't allow you to use await
in the initializer expression).
If you declare a late final
variable without an initializer, you are allowed to write to the variable once. Because the variable is late
, the compiler won't complain about assignments at compile-time, unless it's absolutely certain that you have assigned the variable already, and only if it's a local variable (because that's the only variables that the compiler attempts to track assignments to).
If the late final
variable without an initializer is an instance member of a class, that means that the class interface has a setter. You need to be very, very careful about exposing late final
variables in the public API of a class. (Read: Don't do that!)
It's better to use late variables internally and guard access to the fields, so you can ensure that nobody assigns the variable twice. The goal of a late final variable is not to throw if it's assigned twice. It should never be assigned twice. It's there to allow allow code which knows for some reason that the compiler cannot comprehend, that the variable is only assigning once. So, only allow access to late final variables to code which are aware of that reason, and which maintains the invariant.