The main reason behind the addition of null safety in Dart is that errors caused by unexpected null values are frequent and not always easy to debug.
At the time of writing, not all parts of the Flutter SDK are null safe yet. Some packages are also null safe.
You can still implement null safety in your apps while using null unsafe packages.
In the first code snippet, which you run without null safety, the code raised a runtime error at the following instruction:
value++
This is because you cannot increment a null value.
Simply put, when you enable null safety, by default you cannot assign a null value to any variable, field, or parameter. For instance, in the following code snippet, the second line will prevent your app from compiling:
int someNumber = 42; //this is ok
int someOtherNumber = null; //compile error
In most cases, this should not impact your code. Actually, consider the last code snippet that you wrote for this recipe, which is as follows:
void main() {
int someNumber = 0;
increaseValue(someNumber);
}
void increaseValue(int value) {
value++;
print (value);
}
This is null safe code that should cover most of the scenarios. Here you make sure that a variable actually has a value as follows:
int someNumber = 0;
So when you pass someNumber to the function, you (and the compiler) can be sure that the value parameter will contain a valid integer, and not null.
There are cases though where you may need to use null values and, of course, Dart and Flutter allow you to do that. Only, you must be explicit about it. In order to make a variable, field, or parameter nullable, you can use a question mark after the type:
int? someNumber;
With the preceding code, someNumber becomes nullable, and therefore you can assign a null value to it.
Dart will still not compile the following code though:
void main() {
int? someNumber;
increaseValue(someNumber);
}
void increaseValue(int? value) {
value++;
print (value);
}
This is probably the most interesting part of this recipe: someNumber is explicitly nullable, and so is the value parameter, but still this code will not compile. The Dart parser is smart enough to note that when you write value++, you risk an error, as value can be null, and therefore you are required to check whether value is null before incrementing it. The most obvious way to do this is with an if statement:
if (value != null) {
value++;
} else {
value = 1;
}
But this may add several lines of code to your projects.
Another more concise way to achieve the same result is to use the null-coalescing operator, which you write with a double question mark:
value = value ?? 0;
In the preceding instruction, value takes 0 only if value itself is null, otherwise it keeps its own value.
Another very interesting code snippet we used in this recipe is the following:
void main() {
int? someNumber;
increaseValue(someNumber!);
}
void increaseValue(int value) {
value++;
print (value);
}
In the preceding code, someNumber may be null (int? someNumber), but the value parameter cannot (int value). The exclamation mark (someNumber!) will explicitly force the value parameter to accept someNumber. Basically, here you are telling the compiler, "Don't worry, I will make sure someNumber is valid, so do not raise any error." And after running the code, you get a runtime error.
Implementing null safety is a good way to write code. The main issue with this new (at the time of writing) feature is that not all libraries have been migrated to null safety yet, so you might still get unexpected null values in your code when you use them. Once this transition period is over though, we might expect Flutter apps to be more solid and secure.