Null Safety In Dart
Tags: nullsafety, dart, flutter, codequality
Published: 2020-06-30 07:53:24

Null safety is something implemented in many languages till now. In Dart it is coming with a next level. 

# What is Null Safety ?

The basic goal with Null Safety is to avoid null reference exceptions at runtime. Instead all these errors will be shown at compile time.
1.So it will provide you a __better development__ environment with less runtime errors.
2.Since errors will be pushed forward during compile time, we can use it to __optimize__ our code.
3.It will generate __smaller code__ because we will remove null checks like *if(something != null)*.
4.It will make sure that wherever we are using null, we are using it safely.

#Let's see some code

Go ahead and open 2 tabs with following links to see the difference 
[https://dartpad.dev/](https://dartpad.dev/)
[https://nullsafety.dartpad.dev/](https://nullsafety.dartpad.dev/)
and copy this code in both the pads-  
```dart
void main() {
  print(serveCoffee('ice'));  
}

String serveCoffee(String coffeeType) {
  return coffeeType + ' coffee';
}
```
In the above example we are passing a coffee type into the *serveCoffee() method*. Now we have 2 versions of **DartPad** open. One with null safety enabled and the other without null safety. 
Instead of passing **'ice'** pass null when calling the method And Notice the change - 
```dart
print(serveCoffee(null));
```
The null safety dartpad will give you an error while the traditional dartpad won't.
Let's close the old dart pad and code in the *nullsafety dartpad*
So that's cool. Let's see something even better. 
Make the argument *coffeeType* an optional argument.

```dart
String serveCoffee([String coffeeType]) { // coffeeType is now an optional argument
  return coffeeType + ' coffee';
}
void main() {
  print(serveCoffee('ice'));
  print(serveCoffee()); // here coffeeType will be null
}

```
*Since we declared datatype of coffeeType as String, the null safety check will give an error on line 1.*


![Error Image](https://dev-to-uploads.s3.amazonaws.com/i/aiw90y9jteayt734az8f.png)

**But Wait** What if we want **null** values in optional parameters ??? 
We change the String type in parameter to allow null and we do it this way -- 

```dart
 String serveCoffee([String? coffeeType])
```
Doing this will give you an error on line 2 as 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w9r48zwlddzqiafcj8w0.png)

## Wait Wait Wait! This is just getting interesting.

In above code you are telling the compiler that you will handle the null case by yourself. BUT you have not done so.

So, let's handle the null case. 

```dart
String serveCoffee([String coffeeType]) {
 if(coffeeType == null) {
  return 'hot coffee';
 }
 return coffeeType + ' coffee';
}
void main() {
  print(serveCoffee('ice'));
  print(serveCoffee());
}

```

BOOM! The error is gone because now the compiler knows that you have handled the null case and the code will not go beyond the if statement.

# What to do if we know that the value won't be null ??

Definitely we don't want to use the redundant if statement...
We will use the bang operator(!) instead.

```dart
String serveCoffee([String? coffeeType]) {
 return coffeeType! + ' coffee';
}
void main() {
  print(serveCoffee('ice'));
  print(serveCoffee()); // This will give error on runtime.
}
```

Here we are telling the compiler that we will not pass any null value to the optional argument.


# How do we do this for class variables ?

Suppose we have the following code and we know **setHot()** method will always be called before **serve()** method.
But how do we tell this to the compiler ???
```dart
class Coffee {
 String _coffeeType;
 
  
  void setHot() {
    _coffeeType = 'Hot ';
  }
  
  String serve() => _coffeeType + 'Coffee';
  
}
```

When the compiler checks the above code statically, it sees that _coffeeType is not initialized and can be null in the serve() method, so it gives an error.

## How do we fix that ??

<mark>There are 3 possible ways</mark> and let's get started with the simplest one. 
We will initialise _coffeeType in the class constructor:

```dart
class Coffee {
 String _coffeeType;
 Coffee(): _coffeeType= 'Cold';
  
  void setHot() {
    _coffeeType = 'Hot ';
  }
  
  String serve() => _coffeeType + 'Coffee';
  
}
```
The error is gone because now the compiler knows that it won't be null.

2nd way is to make _coffeeType a nullable String and use the bang operator

```dart
class Coffee {
 String? _coffeeType;
  
  void setHot() {
    _coffeeType = 'Hot ';
  }
  
  String serve() => _coffeeType! + 'Coffee'; // bang operator
  
}
```

# Here comes the new player <mark>'__late__'</mark> keyword

```dart
class Coffee {
 late String _coffeeType;
  
  void setHot() {
    _coffeeType = 'Hot ';
  }
  
  String serve() => _coffeeType + 'Coffee';
  
}
```
Now we are telling the compiler to not check it statically and see it at runtime.
Note if you pass a null value it will give a runtime exception.

That's all from my side on null safety in dart.

*You can explore it even further on the null safety dart pad where on the top right corner you have an option of learning with snippets.*


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/caepy6l6zaxrdm0j8ui2.png)


Do let me know your thoughts on this in the comments below ...