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?
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.)
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{
}
Related
I wonder if there's a language sugar/SDK utility function in Dart that allows to protect a certain code from running more than once?
E.g.
void onUserLogin() {
...
runOnce(() {
handleInitialMessage();
});
...
}
I know I can add a global or class static boolean flag to check but it would be accessible in other functions of the same scope with a risk of accidental mixup in the future.
In C++ I could e.g. use a local static bool for this.
There is no built-in functionality to prevent code from running more than once. You need some kind of external state to know whether it actually did run.
You can't just remember whether the function itself has been seen before, because you use a function expression ("lambda") here, and every evaluation of that creates a new function object which is not even equal to other function objects created by the same expression.
So, you need something to represent the location of the call.
I guess you could hack up something using stack traces. I will not recommend that (very expensive for very little advantage).
So, I'd recommend something like:
class RunOnce {
bool _hasRun = false;
void call(void Function() function) {
if (_hasRun) return;
// Set after calling if you don't want a throw to count as a run.
_hasRun = true;
function();
}
}
...
static final _runOnce = RunOnce();
void onUserLogin() {
_runOnce(handleInitialMessage);
}
It's still just a static global that can be accidentally reused.
What is the logic here when the programmer initializes _random at once but the _streamController is initialized in the constructor?
Can all the fields be initialized without a constructor then?
RandomStore {
RandomStore() {
_streamController = StreamController<int>();
_timer = Timer.periodic(const Duration(seconds: 1),
(_) => _streamController.add(_random.nextInt(100)));
randomStream = ObservableStream(_streamController.stream);
}
late final Timer _timer;
final _random = Random();
late final StreamController<int> _streamController;
late final ObservableStream<int?> randomStream;
...
Can all the fields be initialized without a constructor ?
Yes, you can initialize all fields without having to declare a constructor, but only if you don't need a reference to the current instance (this) or if they are 'late' fields.
The determining factor in choosing where to initialize fields is whether or not you need to have the reference (even implicit) to this.
In Dart this is only available from the construcor body; this means in particular that this is not usable in the initializer list and inside the inline initializers (except for the late fields).For terminology, see Glossary below.
this is the reference to the current instance, and is required in order to read the instance fields, even if you usually omit it (e.g., in your snippet, randomStream is equivalent to this.randomStream).
For example, in your snippet, to initialize randomStream you need to be able to read the streamController field, so you have to mark it with late; thanks to late you can initialize randomStream in the constructor body or in the inline initializer (in this second case it will actually be initialized only when you try to access it for the first time; which is an advantage if its initialization is expensive and you want to avoid it as long as possible).
As an alternative to late, you could mark the field as nullable and initialize it in the constructor body (in which case the field will first be implicitly initialized with a null value; in fact this approach is not usable if the field is final and therefore cannot be reassigned).
Instead, to initialize the streamController field, you don't use a reference to this, so you could avoid the overhead of marking the field with late and you can initialize it in the initializer list or in the inline initializer (it is the same).
Example:
class RandomStore {
final StreamController<int> _streamController;
RandomStore()
: _streamController = StreamController<int>() {
}
}
Is late always a good choice? (UPDATED)
While from the above it might seem that 'late' is a great solution for most situations, the doc suggests avoiding 'late' if it is not really necessary, because:
It is less secure:
a late field (also if it has a non-nullable type) entails a risk of errors at runtime similar to that which occurred before the introduction of sound null safety, because Dart does not force you to perform any checks before reading its value (unlike nullable fields, for which access to properties requires the use of not null operator or conditional operator). Note that Dart does not offer the possibility to check if a late field has already been initialized (See Issue #324 mentioned below)
It adds overhead:
under the cover will be created a field with the indicated type, a field -presumably boolean- for keep track of whether the initialization has occurred, and a getter that at each access checks if the initialization had occurred.
Useful sources about late:
Doc Guide about null safety and late variables https://dart.dev/null-safety/understanding-null-safety#late-variables
Dart Best practice about late
https://dart.dev/guides/language/effective-dart/usage#dont-use-late-when-a-constructor-initializer-list-will-do
https://dart.dev/guides/language/effective-dart/usage#avoid-late-variables-if-you-need-to-check-whether-they-are-initialized
Dart issue #324 Should we provide a way to query the status of late variables?
a very interesting insight into 'late' (the discussion in which the Dart Team decided not to allow the final developers to check if a late field has been initialized)
Note the differences with Java:
(which personally made it difficult for me to switch from Java to Dart at first)
this in Dart is not available in inline initializers (in Java it is available)
the final fields in Dart must be initialized before the constructor body (in Java they can also be initialized in the constructor body)
Gloassary:
class MyClass {
MyClass(String v1, String v2)
: myField1 = v1, myField2 = v2 //This is the "initializer list"
//Compared to inline initializers, it allows you to initialize fields using the constructor arguments
{
//This is the "constructor body"
myField4 = myField1; //This operation require an implicit reference to `this`; it is equivalent to `myField4 = this.myField1;`
}
String myField1;
String myField2;
String myField3 = '3'; //This is the "inline initialization"
late String myField4;
}
I recently found out it was possible to include final in function parameters.
/// Handler for the footer leading checkbox
void _onCheck(final bool value) {
setState(() {
_checked = value;
});
}
However, this feature is not documented anywhere and it's impossible to search any information regarding this topic.
Since the value being passed to the function was already declared elsewhere and could've used var, what are the impacts of using final in function parameters?
It works like declaring any other variable as final - the variable cannot be changed after it has been initialized.
A parameter is really just a local variable where the initializing value comes from the caller instead of a local expression.
So here, you would get an error if you write value = false; in the function because value is a final variable. You would get no error if you removed the final.
Other than that, there is no difference.
Coming back to C++ after a hiatus in Java. Attempting to create an immutable object and after working in Java, a public const variable seems the most sensible (like Java final).
public:
const int A;
All well and good, but if I want to defensive check this value, how might I go about it. The code below seems strange to me, but unlike Java final members, I can't seem to set A in the constructor after defensive checks (compiler error).
MyObj::MyObj(int a) : A(a) {
if (a < 0)
throw invalid_argument("must be positive");
}
A public const variable for A seems like a clearer, cleaner solution than a getter only with a non const int behind it, but open to that or other ideas if this is bad practice.
Your example as it stands should work fine:
class MyObj {
public:
const int var;
MyObj(int var) : var(var) {
if (var < 0)
throw std::invalid_argument("must be positive");
}
};
(Live example, or with out-of-line constructor)
If you intend that MyObj will always be immutable, then a const member is
probably fine. If you want the variable to be immutable in general, but still have the possibility to overwrite the entire object with an assignment, then better to have a private variable with a getter:
class MyObj {
int var;
public:
MyObj(int var) : var(var) {
if (var < 0)
throw std::invalid_argument("must be positive");
}
int getVar() const { return var; }
};
// now allows
MyObj a(5);
MyObj b(10);
a = b;
Edit
Apparently, what you want to do is something like
MyObj(int var) {
if (var < 0)
throw std::invalid_argument("must be positive");
this->var = var;
}
This is not possible; once a const variable has a value it cannot be changed. Once the body ({} bit) of the constructor starts, const variables already have a value, though in this case the value is "undefined" since you're not setting it (and the compiler is throwing an error because of it).
Moreover, there's actually no point to this. There is no efficiency difference in setting the variable after the checks or before them, and it's not like any external observers will be able to see the difference regardless since the throw statement will unroll the stack, deconstructing the object straight away.
Generally the answer by N. Shead is the regular practice - but you can also consider:
Create domain-specific types and use them instead of general primitives. E.g., if your field is a telephone number, have a type TelephoneNumber which, in its constructor (or factory), taking a string, does all the telephone number validation you'd like (and throws on invalid). Then you write something like:
class Contact {
const TelephoneNumber phone_;
public:
Contact(string phone) : phone_(phone) { ... }
...
When you do this the constructor for TelephoneNumber taking a string argument will be called when initializing the field phone_ and the validation will happen.
Using domain-specific types this way is discussed on the web under the name "primitive obsession" as a "code smell".
(The problem with this approach IMO is that you pretty much have to use it everywhere, and from the start of your project, otherwise you start having to have explicit (or implicit) casting all over the place and your code looks like crap and you can never be sure if the value you have has been validated or not. If you're working with an existing codebase it is nearly impossible to retrofit it completely though you might just start using it for particularly important/ubiquitous types.)
Create validation methods that take and return some value, and which perform the validation necessary - throwing when invalid otherwise returning its argument. Here's an example validator:
string ValidatePhoneNumber(string v) {
<some kind of validation throwing on invalid...>
return v;
}
And use it as follows:
class Contact {
const string phone_;
public:
Contact(string phone) : phone_(ValidatePhoneNumber(phone)) { ... }
I've seen this used when an application or library is doing so much validation of domain-specific types that a small library of these domain-specific validator methods has been built up and code readers are used to them. I wouldn't really consider it idiomatic, but it does have the advantage that the validation is right out there in the open where you can see it.
TL;DR: Named parameters are optional as a result of a conscious design choice. Short of having official language support, is there any way to enforce (and inform) required named arguments?
I find it extremely useful to use named parameters when defining a class. Take, for instance, an Ability in an MMORPG:
class Ability {
final name;
final effectDuration;
final recast; // wait time until next use
// ...
}
effectDuration and recast both carry the same type of information (i.e. duration of time) and are likely represented by the same datatype. It is easy to mix up which number goes where. However, they are both information vital to the correctness of the object, so they can't be missing during instantiation.
I could just break the program via a try-catch to enforce the requirement of those parameters, but that doesn't sound like fun for someone who uses the class and has no idea (short of reading the docs and understanding intuitively what the class does) that they are required.
Is there any way to enforce the requirement of certain named parameters while managing to inform the caller of said requirement and/or help them use it correctly?
The meta package provides a #required annotation that is supported by the DartAnalyzer.
Flutter uses this a lot and provides #required directly from import 'package:flutter/foundation.dart'
foo({#required String name}) {...}
foo(); // results in static warning
#required doesn't check if the passed value is null or not, only that a value was actually passed on the call site.
To check for null you can also use assert() to check for passed values
class Ability {
Ability(this.name, this.effectDuration, this.recast) : assert(name != null), assert(effectDuration != null), assert(recast != null);
final name;
final effectDuration;
final recast; // wait time until next use
// ...
}
[Update] New as-of Dart 2.0
In dart 2.0 the required keyword has been added to the language as part of the null-safety update. This means that you get a compiler-enforced non-null value rather than one checked by the analyzer; this makes the null check completely redundant.
This means that this code does effectively the same as the old code below, except that you never have to worry about the assertion throwing as the values for name, effectDuration, and recast cannot be null.
class Ability {
final String name;
final Duration effectDuration;
final bool recast;
final String? description;
Ability({
required this.name,
this.effectDuration = Duration(seconds: 1),
this.recast = false,
this.description,
});
}
Before Dart 2.0
Yes, there is!
Here's an example:
class Ability {
final String name;
final Duration effectDuration;
final bool recast;
final String description;
Ability({
#required this.name,
this.effectDuration = new Duration(seconds: 1),
this.recast = false,
this.description,
}):
assert(name != null),
assert(effectDuration != null);
}
You don't have to assert that name is not equal to null, but it might be useful for you.
Although you could use the flutter foundation package as described in the accepted answer, when I am working with model classes that don't need to know about Flutter, I prefer to use the meta package directly. That way it doesn't create an unnecessary dependency on the framework. This allows you to share the Dart code even outside of Flutter.
Add meta to pubspec.yaml:
dependencies:
meta: ^1.1.7
Import it in your class file:
import 'package:meta/meta.dart';
Use the #required annotation in your code:
class Person {
String name;
int age;
Person({#required this.name, this.age,});
}
So name is a required parameter, but age isn't.
final person = Person(name: 'Bob');
Update:
In an upcoming version of Dart, the required keyword should be added by default, so no imports will be necessary at all.
As of 2.12 with null safety you can use required keyword (not #required). Also no need to import any additional packages.
In this example named parameter name is optional while effectDuration and recast are required.
class Ability {
final name;
final effectDuration;
final recast;
Ability({this.name, required this.effectDuration, required this.recast});
}
Update pubspec.yaml, for example:
environment:
sdk: ">=2.12.0-0 <3.0.0"
References:
Sound null safety
How does #required compare to the new required keyword?
With null safety:
Non-nullable named parameter:
You need to either mark the named parameter required or provide a default value or even mark it late. For example:
class Foo {
final int a;
final int b;
late final int c; // Mark late and provide value later.
Foo({
required this.a, // Mark required.
this.b = 0, // Provided a default value.
});
}
Nullable named parameter:
You don't need anything special to handle them.
class Foo {
final int? z;
Foo({
this.z,
});
}
If you want declare to a empty variable but that has methods inside , you can:
1)Use the late keyword
2)Declare the type like possible null returned example: int? number;
3)Initialize the variable empty, for example :
List listOfNumbers = [];
Map mapOfPerson1 = {};
And so you can use the methods of the variable to add them values