Getting started with Dart Null Safety : A beginners guide
Dart Null Safety: The first announcement of the Dart null safety as a tech preview was first made early in June this year, another followed it in the later parts of October.
In this article, we will be exploring the Dart language features and all there is to Null Safety in Dart, which the underlying language for the flutter framework, and also go over how to use it.
Dart Null Safety
Null safety is a relatively modern productivity feature that helps us avoid cases of null exceptions in our applications, These exceptions are a set of bugs that are particularly not easily debugged.
Null safety is a great milestone for the language and it also enables performance improvements and it was introduced in Dart v2.9 as a Language feature.
In dart v2.9 all types are non-nullable by default and values that can be nullable have to be specified.
Nullable variables are variable that may either contain a valid value or they may not — in the latter case, they are considered to be null, whereas non-nullable variables must always contain a value and can never be null.
void main(){
String name;
name = null;
print("Name is $name");
}
With the dart’s null safety feature a code like the above one will throw an error and wont compile.
Since all types are non-null by default here, it is always important to always initialize a non-null variable with non-null values. This helps us write null-safe code with strong compile-time guarantees.
Importance of Null Safety
Dart Programming Language is a type-safe language. This means that when you declare a variable for instance a string, it cannot be assigned to an int or any other variable. Let’s Look at the code snippet below for an example.
void main() {
String name;
name= 2;
}
Looking at the code above. Can you spot the issue? Well, the string variable name can obviously not be assigned a value of int and as a result, the compiler throws an error.
Although this is great for avoiding exceptions, this does not necessarily guarantee that the variable in itself is not null and will not be null during runtime, and this can cause our application to throw an exception during.
One importance of the null safety feature is that we can not catch null errors at compile time rather than at runtime.
Let’s take another case into considerations and learn about how null safety can make our lives easier.
List<File> newFile;
void main(){
printLengths(newFile);
}
void printLengths(List<File> files) {
for (var file in files) {
print(file.lengthSync());
}
}
The code above appears to work very fine, but will create a null exception during runtime. Now, this can be easily spotted when dealing with a few lines of code, but a production level can pose as a serious bug that can encumber a developer and prolong our development time.
This is why Dart’s sound null safety is implemented to check this while you code. Without null safety, code like the one in the above snippet will not compile.
The code snippet above will produce an error with the new dart null safety feature.
Working with Nullable in Dart
Dart still provides a way to declare nullable values. This can be done by adding a question mark to the type parameter and this tells the compiler that this value can be allowed to be null.
void main() {
String? name;
name= null;
}
The code above will not throw an error, subsequently we can also reassign the non-value to variable name and it still will not be a problem to the compiler.
void main() {
String? name;
name= null;
name="Mike";
}
Type Promotion with Null Checks in Dart
There are times when we declare nullable values and they can be a problem to the compiler. Lets take a look at the example below.
void printNameLength(String? name) {
print(name.length);
}
The code above will not compile and this is because, the operation carried out the name variable, will definitely throw an error is the variable is empty.
One way to solve this is by carrying out a null check on the variable which will promote the value to a non-null value and then we can carry out any operation on the variable.
Adding this to the code snippet above would look something like this.
void printNameLength(String? name) {
if (name == null) {
return;
}
print(name.length);
}
In order to promote this variable the compiler has to confirm that the value is not null and once this happens, the variable can be promoted to a non-nullable value.
Using Non-Nullable Values with Classes
Instance variables in classes must be initialized if they are non-nullable, this means that we can write code like the first class, but the second one will throw an error.
class Codesource{
String name = "My name";
}
class CodeSource{
String name;
}
A solution to the error thrown by the compiler in the case of the second class is the set it with our constructor like this.
class CodeSource{
CodeSource(this.name);
String name;
}
Definite Assignment
The dart compiler knows exactly when variables are created, assigned and also when they are read.
Let’s take a close look at the code below.
String name(String name) {
String value; // non-nullable by default
print(value.length()); // invalid: 'value' must be assigned before it can be used
if (name.isNotEmpty) {
value= name;
} else {
value = "No name provided";
}
print(value); // This will not throw any errors
return value;
}
From the above code on line 3, the compiler tells us it is not happy because we are trying to read from a value that has not been initialized and after it has been assigned a value on line 5, the next time we try to read it throws no errors.
Late Keyword
The late keyword can be employed to denote variables that are not initialized immediately they are created, but whenever they are accessed. This implies that we can have non-null instance fields that will be initialized later on.
class ExampleState extends State {
late final String name; // non-nullable by default
@override
void initState() {
super.initState();
// print(name) here would throw null exception at runtime
name= 'Mike';
}
}
Conclusion
From the foregoing, we can see how useful the new language feature of Dart, which is Sound Null Safety is a great benefit and can also make the dart compiler unhappy if used wrongly.
Always remember to use the null aware operator? with variable types or named parameters in which you see the need to declare null aware, to reduce compile-time errors.
You can always refer to the official docs on null safety for more information.