What is the best practice for checking nulls in Dart?
var value = maybeSomeNumber();
if (value != null) {
doSomething();
}
That’s right. There is no shortcut like if (value)
and truthy/falsey values in Javascript. Conditionals in Dart only accept bool
values.
However! There are some very interesting null-aware operators.
??
In other languages we can use the logical-or shortcut. If maybeSomeNumber()
returns null, assign a default value of 2
:
value = maybeSomeNumber() || 2
In Dart we can’t do this because the expression needs to be a boolean (“the operands of the ||
operator must be assignable to bool
”).
That’s why the ??
operator exists:
var value = maybeSomeNumber() ?? 2;
Similarly, if we wanted to ensure a value
argument was not-null we’d do:
value = value ?? 2;
But there’s an even simpler way.
??=
value ??= 2;
Much like Ruby’s ||=
, it assigns a value if the variable is null.
Here’s an example of a very concise cache-based factory constructor using this operator:
class Robot {
final double height;
static final _cache = <double, Robot>{};
Robot._(this.height);
factory Robot(height) {
return _cache[height] ??= Robot._(height);
}
}
More generally, ??=
is useful when defining computed properties:
get value => _value ??= _computeValue();
?.
Otherwise known as the Elvis operator. I first saw this in the Groovy language.
def value = person?.address?.street?.value
If any of person
, address
or street
are null, the whole expression returns null. Otherwise, value
is called and returned.
In Dart it’s exactly the same!
final value = person?.address?.street?.value;
If address
was a method instead of a getter, it would work just the same:
final value = person?.getAddress()?.street?.value;
...?
Lastly, this one only inserts a list into another only if it’s not-null.
List<int> additionalZipCodes = [33110, 33121, 33320];
List<int> optionalZipCodes = fetchZipCodes();
final zips = [10001, ...additionalZipCodes, ...?optionalZipCodes];
print(zips); /* [10001, 33110, 33121, 33320] if fetchZipCodes() returns null */
Right now, null
can be assigned to any assignable variable.
There are plans to improve the Dart language and include NNBD (non-nullable by default).
For a type to allow null values, a special syntax will be required.
The following will throw an error:
int value = someNumber();
value = null;
And fixed by specifying the int?
type:
int? value = someNumber();
value = null;