There is an updated edition of this book available! View Latest Edition

# 7 Nullability

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

You know that game where you try to find the item that doesn’t belong in a list? Here’s one for you:

``````horse, camel, pig, cow, sheep, goat
``````

Which one doesn’t belong?

It’s the third one, of course! The other animals are raised by nomadic peoples, but a pig is a farmer’s animal — it doesn’t do so well trekking across the steppe. About now you’re probably muttering to yourself why your answer was just as good — like, a sheep is the only animal with wool, or something similar. If you got an answer that works, good job. Here’s another one:

``````196, 144, 169, 182, 121
``````

Did you get it? The answer is one hundred and eighty-two. All the other numbers are squares of integers.

One more:

``````3, null, 1, 7, 4, 5
``````

And the answer is . . . `null`! All of the other items in the list are integers, but `null` isn’t an integer.

What? Was that too easy?

## Null overview

In the example above, `null` was the odd value out, but in Dart, it actually fits in… for now. Every type can contain the value of `null` in addition to its own data type. Here are a few more examples of `null` in use:

• `double`: `3.14159265`, `0.001`, `100.5`, `null`
• `bool`: `true`, `false`, `null`
• `String`: `'a'`, `'hello'`, `'Would you like fries with that?'`, `null`
• `User`: `ray`, `vicki`, `anonymous`, `null`

That means you can set any type to `null`:

``````int myInt = null;
double myDouble = null;
bool myBool = null;
String myString = null;
User myUser = null;
``````

If you’re getting the following error:

``````A value of type 'Null' can't be assigned to a variable of type 'int'
``````

That means you’re from the future. The code above was written back in 2020 before Dart got its major upgrade for sound null safety. Never fear, though, there’s still a lot even you future dwellers can learn in this chapter.

The first two major sections of this chapter, “Null overview” and “Null-aware operators” will describe nullability in Dart as it exists at the time of writing. The final major section, “Null safety preview”, will describe what sound null safety is all about.

### What null means

Null means “no value” or “absence of a value”. It’s quite useful to have such a concept. Imagine not having null at all. Say you ask a user for their postal code so that you can save it as an integer in your program:

``````final postalCode = 12345;
``````
``````final postalCode = -1;
``````
``````// Hey everybody, -1 means that the user
// doesn't have a postal code. Don't forget!
final postalCode = -1;
``````
``````final postalCode = null;
``````

### The problem with null

As useful as `null` is for indicating an absence of a value, developers do have a problem with it. The problem is that they tend to forget that it exists. And when developers forget about `null`, they don’t handle it in their code. Those nulls are like little ticking time bombs ready to explode your code.

``````bool isPositive(int anInteger) {
return !anInteger.isNegative;
}
``````
``````isPositive(null);
``````
``````NoSuchMethodError: The getter 'isNegative' was called on null.
``````

If you’re sure that a function won’t ever get called with `null`, you add an `assert` to the beginning of the function:

``````bool isPositive(int anInteger) {
assert(anInteger != null);
return !anInteger.isNegative;
}
``````

#### Handling null inside a function

The other option is to allow `null` in the function, but to handle it appropriately. Since `null` is “no value”, it’s logical to say that it also isn’t positive.

``````bool isPositive(int anInteger) {
if (anInteger == null) {
return false;
}
return !anInteger.isNegative;
}
``````
``````print(isPositive(null));
``````

### Null by default

For any variable in Dart, if you don’t initialize the variable, it’ll be given the default value of `null`. All Dart types, even basic types like `int` and `double`, are derived from the type named `Object`. If you don’t initialize an object, it takes on a `null` value.

``````int age;
double height;
String message;
``````
``````print(age);
print(height);
print(message);
``````

## Null-aware operators

Dart has a set of operators that can help you handle null values. Here they are in brief:

### If-null operator (??)

One very convenient way to handle `null` values is to use the double question mark, also known as the if-null operator. This operator says, “If the value on the left isn’t `null`, then use it; otherwise, go with the value on the right.”

``````String message;
var text = message ?? 'Error';
``````
``````Error
``````
``````message = 'Greetings!';
text = message ?? 'Error';
``````
``````Greetings!
``````
``````var text;
if (message == null) {
text = 'Error';
} else {
text = message;
}
``````

### Null-aware assignment operator (??=)

In the example above, you introduced a new variable named `text`. However, in that particular case, it was just adding extra complexity. Since you declared `message` using `var`, you can reassign it like so:

``````message = message ?? 'Error';
``````
``````x = x + 1;
x += 1;
``````
``````message ??= 'Error';
``````

### Null-aware access operator

Earlier with `anInteger.isNegative`, you saw that trying to access the `isNegative` property when `anInteger` was `null` caused a `NoSuchMethodError`. There’s also an operator for null safety when accessing object members. The null-aware access operator returns `null` if the left-hand side is `null`. Otherwise, it returns the property on the right-hand side.

``````int age;
print(age?.isNegative);
``````
``````null
``````
``````print(age?.toDouble());
``````

### Mini-exercises

1. Create a `String` variable called `profession`, but don’t give it a value. Then you’ll have `profession` `null`. :]
2. Use the null-aware access operator to print the `length` of `profession` without causing an error.
3. Pretend you don’t know if `profession` is `null` or not, and use the null-aware assignment operator to give `profession` a value of “basketball player”.

## Null safety preview

Welcome to the future!

### Getting set up

For those of you still living in the 2.10 Dart ages, when sound null safety hadn’t yet entered the SDK, you’ll need to use another method besides VS Code to test the examples below. DartPad has just the thing. Go to nullsafety.dartpad.dev.

### Non-nullable by default

In previous versions of Dart, if you had a variable or parameter or return value, it was `null` by default if you didn’t initialize it with a value. However, now Dart variables are non-nullable by default. If you don’t initialize a variable, you’ll get an error.

``````String myString;
print(myString);
``````
``````The non-nullable local variable 'myString' must be assigned before it can be used
``````
``````String myString = 'I love non-nullable types!';
``````
``````3, null, 1, 7, 4, 5
``````

#### Optional nullability

As you know, though, `null` isn’t all bad. It’s very useful for indicating “no value”. However, if you do want a nullable value, you have to tell that to Dart. You do that by adding `?` after the type name.

``````String? myString;
print(myString);
``````

#### Guaranteed value

Since only types that end in a question mark can potentially have a `null` value, every time you see a type without a question mark, you can be absolutely positive that it won’t ever be `null`.

``````bool isPositive(int anInteger) {
if (anInteger == null) {
return false;
}
return !anInteger.isNegative;
}
``````
``````The operand can't be null, so the condition is always false
``````
``````bool isPositive(int anInteger) {
return !anInteger.isNegative;
}
``````

### Initializing non-nullable class fields

Since only nullable variables can be `null`, Dart requires you to you give a non-nullable member variable in a class an initial value before you use it.

``````class User {
String name;
}
``````

#### Using initializers

One way to initialize a field is to use an initializer value:

``````class User {
String name = 'anonymous';
}
``````

#### Using initializing formals

Another way to initialize a field is to use an initializing formal, that is, by using `this` in front of the field name:

``````class User {
User(this.name);
String name;
}
``````

#### Using an initializer list

You can also use an initializer list to instantiate a field variable:

``````class User {
User(String name)
: _name = name;
String _name;
}
``````

#### Using default parameter values

You recall that optional parameters default to `null` if you don’t set them. So for non-nullable types, that means you must provide a default value.

``````class User {
User([this.name = 'anonymous']);
String name;
}
``````
``````class User {
User({this.name = 'anonymous'});
String name;
}
``````

#### Required named parameters

If you want to make a named parameter required, there’s now a new `required` keyword. This replaces the `@required` annotation that you learned about in Chapter 5.

``````class User {
User({required this.name});
String name;
}
``````

#### Nullable fields

All of the methods above guaranteed that the class field will be initialized, and not only initialized, but initialized with a non-null value. Since the field is non-nullable, it’s not even possible to make the following mistake:

``````final user = User(name: null);
``````
``````The argument type 'Null' can't be assigned to the parameter type 'String'
``````
``````class User {
String? name;
}
``````

### Handling nullable values

The reason that it’s hard to forget to handle `null` is that if you’re working with nullable values, there isn’t much you can do with them.

``````String? name;
print(name.length);
``````

``````Property 'length' cannot be accessed on 'String?' because it is potentially null.
``````

### Type promotion

The Dart analyzer, which is the tool that tells you what the compile-time errors and warning are, is smart enough to tell in a wide range of situations if a nullable variable is guaranteed to contain a non-null value or not.

``````String? name;
name = 'Ray';
print(name.length);
``````
``````String myMethod(int? myParameter) {
if (myParameter == null) {
return 'something';
}
return myParameter.toString();
}
``````

### More null-aware operators

Previously you learned about the `??` and `.?` and `??=` null-aware operators. The new version of Dart adds some more null-aware operators that will help you to get at a variable’s value if it isn’t `null`.

#### Null assertion operator (`!`)

Sometimes Dart isn’t sure whether a nullable variable is `null` or not, but you know it’s not. Dart is smart and all, but machines don’t rule the world yet.

``````String? nullableGreeting = 'hello';
``````
``````String nonNullableGreeting = nullableGreeting!;
``````
``````String nonNullableGreeting = nullableGreeting as String;
``````
``````bool? isBeautiful(String? item) {
if (item == 'flower') {
return true;
} else if (item == 'garbage') {
return false;
}
return null;
}
``````
``````bool flowerIsBeautiful = isBeautiful('flower');
``````
``````A value of type 'bool?' can't be assigned to a variable of type bool
``````
``````bool flowerIsBeautiful = isBeautiful('flower')!;
``````
``````bool flowerIsBeautiful = isBeautiful('flower') ?? true;
``````

#### Null-aware cascade operator (`?..`)

In Chapter 6 you learned about the cascade operator, which allows you to call multiple methods or set multiple properties on the same object.

``````class User {
String? name;
int? id;
}
``````
``````User user = User()
..name = 'Ray'
..id = 42;
``````
``````User? user = User();
``````
``````user
?..name = 'Ray'
..id = 42;
``````
``````String? lengthString = user?.name?.length.toString();
``````

#### Null-aware index operator (`?[]`)

The null-aware index operator is used for accessing the elements of a list when the list itself might be `null`. You’ve used lists already a couple of times in this book, but since you won’t cover them in depth until Chapter 8, this section will just give a simple explanation of how the `?[]` operator is used.

``````List<int>? myList = [1, 2, 3];
``````
``````int? myItem = myList?[0];
``````

### The late keyword

Sometimes you want to use a non-nullable type, but you can’t initialize it in any of the ways you learned above.

``````class User {
User(this.name);

final String name;
final int _secretNumber = _calculateSecret();

int _calculateSecret() {
return name.length + 42;
}
}
``````
``````late final int _secretNumber = _calculateSecret();
``````

#### Dangers of being late

The example above was for initializing a final variable, but you can also use `late` with non-final variables. You have to be careful with this, though. Take a look at the following example:

``````class User {
late String name;
}
``````
``````final user = User();
print(user.name);
``````
``````LateInitializationError: Field 'name' has not been initialized.
``````

#### Benefits of being lazy

Who knew that it pays to be lazy sometimes? Dart knows this, though, and uses it to great advantage.

``````class SomeClass {
late String? value = doHeavyCalculation();
String? doHeavyCalculation() {
// do heavy calculation
}
}
``````

## Challenges

Before moving on, here are some challenges to test your knowledge of nullability. It’s best if you try to solve them yourself, but solutions are available if you get stuck. These are available with the supplementary materials for this book.

### Challenge 1: Random nothings

Write a function that randomly returns `42` or `null`. Assign the return value of the function to a variable named `result` that will never be `null`. Give `result` a default of `0` if the function returns `null`.

### Challenge 2: Naming customs

People around the world have different customs for giving names to children. It would be difficult to create a data class to accurately represent them all, but try it like this:

## Key points

Points ending with an asterisk (*) only apply to the sound null safety update in Dart, not to Dart 2.10 or earlier.

``````??    if-null operator
??=   null-aware assignment operator
?.    null-aware access operator
?.    null-aware method invocation operator
!     null assertion operator*
?[]   null-aware index operator*
Keep your eyes open for the big sound null safety upgrade in Dart. Most of the examples in the other chapters of this book will still work, but for a few of them, you’ll need to make some minor adjustments, such as adding `?` after the type name to make it nullable.