Let say I have class like this
class OrderInfo {
final String orderId;
final String status;
final DateTime orderDateTime;
final DateTime? deliverDateTime;
final String? restaurantTitle;
OrderInfo({
required this.orderId,
required this.status,
required this.orderDateTime,
required this.deliverDateTime,
required this.restaurantTitle,
});
// and a getter
Something get something {
// Very long code that I don't want to recalculate
return something;
};
}
Since all fields is final
, so there's no point to recalculate (return value will be the same).
I tried create field like this.
late Something something = () {
// Very long code that I don't want to recalculate
return something;
}();
But I'm not sure this is correct way to do. Is there other method or this is fine?
CodePudding user response:
The late field is fine. I'd make it final
, unless you want to allow overwriting the value.
I'd probably extract the computation function into a named helper function, like:
class OrderInfo {
late final Something something = _computeSomething();
...
Something _computeSomething() {
// Very long code that I don't want to recalculate
return something;
}
}
Keeping the computation on the side makes the variable declaration more readable, and it allows you to reuse _computeSomething
if you want to, but otherwise the effect is the same.
If the Something
cannot be null
, you can also implement your own late variable:
class OrderInfo {
Something? _something;
...
Something get something => _something ??= _computeSomething();
...
}
The only advantage over a late final .. = ...
is that it allows you to check whether the _something
has been computed or not.
In some cases that's useful. Say the computation allocates a resource, and you want to release that resource later. If you just use a late
variable to store the allocated value, all you can do is read that variable or not. Reading it will allocate the resource, if it wasn't already, and then you have to release it.
Using a nullable variable, you can check whether there is something to release, and do nothing if not.
In general, if you ever need to know whether a late
variable has been initialized, consider not using late
to begin with, because late
hides the "is initialized" bit from you.
Hiding details is what makes the late final something = ...;
so nice and short, so using late final
is fine when you don't need to know.
(I'd generally recommend against exposing late
public fields that are not final
, or that do not have an initializing expression, because that will also expose a setter for the field. It either exposes the potentially uninitialize field to your users, risking it throwing when read, or it exposes a setter in your API that users cannot call anyway. A late final
variable with an initializer expression is great, because it doesn't have a setter, and it is always initialized when it's read.)
CodePudding user response:
save result into a final variable, then the getter only take the result, it will not recalculate :
class OrderInfo {
final String orderId;
final String status;
final DateTime orderDateTime;
final DateTime? deliverDateTime;
final String? restaurantTitle;
late final Something _somethingFinal;
OrderInfo({
required this.orderId,
required this.status,
required this.orderDateTime,
required this.deliverDateTime,
required this.restaurantTitle,
}){
_somethingFinal = _calculateSomthing();
}
// and a getter
Something get something {
// Very long code that I don't want to recalculate
return _somethingFinal;
}
Something _calculateSomthing(){
return Something();
}
}
class Something{
}