The idiomatic way to write this code is:
class Balance{
final String currency;
final Money receivable;
final Money payable;
Balance(this.currency, {Money? receivable, Money? payable})
: receivable = receivable ?? Money.from(0, code: currency),
payable = payable ?? Money.from(0, code: currency);
}
(plus documentation!)
By initializing the fields in the initializer list (which exists for exactly that reason), you can make the fields final and non-nullable an still initialize them using computations that rely on arguments.
I'd never use late
for a public field. In this case, you actually do initialize it immediately in the constructor, so there is no risk of clients of the class accidentally reading the field before it's initialized. They just don't know that, all they see is that the field is late
.
Even if you make the field final
, a late final
field with no initializer will still have a setter visible in the public API.
If you actually want the fields to be mutable, then you can remove the final
. Then being late
isn't as bad, as long as you still ensure that the fields are initialized before anyone else sees the object. Then you still usually do what I did here instead and avoid the late
.
The one case where you might need late
is when you need to create a cyclic structure of final fields. Something like
class MainNode {
final String name;
late final SubNode _sub;
MainNode(this.name, String data) {
_sub = SubNode(this, data);
}
SubNode get sub => _sub;
}
class SubNode {
final MainNode parent;
String data;
SubNode(this.parent, this.data);
}
For something like this, where you need to create the sub-node after you have access to this
, a late final
field makes sense, and ensures that _sub
is actually only written once. (I avoid exposing the _sub
setter in the API by making it private, though.)