Checking Nulls and Null-Aware Operators in Dart

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.

Default operator: ??

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.

Fallback assignment operator: ??=

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();

Safe navigation operator: ?.

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;

groovy

Optional spread operator: ...?

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 */

Non-nullable types

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;