Dart added the late
keyword as part of their null safety release and it is very useful, particularly for testing. As a quick review null safety means telling the compiler that some variables will never be null. Any variable declared without a question mark following the type declaration is null safe. So String name
is null safe while String? name
can be null. Given that the question mark is new syntax all code written before null safety was introduced now declares all variables as cannot be null. The new late
keyword tells the compiler that although a variable is not declared null safe, in practice it will never be null when accessed. Code is then added at runtime to ensure that the variable is not null when used. The compiler cannot perform any checks for you, so it’s not as good as full null safety but it can be convenient, particularly for tests. An example should make it clearer.
Example
Before null safety here is a common pattern that I used in unit tests to ensure that the class is reinitialized before each test while not having to put the constructor in the test.
import 'package:flutter_test/flutter_test.dart';
class Accumulator {
int _currentTotal = 0;
int add(int val) => _currentTotal += val;
int get currentTotal => _currentTotal;
}
void main() {
Accumulator accumulator;
setUp(() {
accumulator = Accumulator();
});
test('starts at 0', () async {
expect(accumulator.add(2), 2);
});
test('accumulates', () async {
expect(accumulator.add(2), 2);
expect(accumulator.add(2), 4);
});
}
Null Safe Version
This code won’t compile with sound null safety because accumulator
isn’t declared as nullable and isn’t initialized. The simplest way to fix that would be to make it nullable by changing the declaration to:
Accumulator? accumulator;
However, that means adding either ?
or !
to every use. The new late
keyword offers an excellent alternative. Change the declaration to:
late Accumulator accumulator;
The compiler is now happy and if accumulator
is ever not initialized before use it will be caught at runtime because Dart inserts runtime checks around every use of that variable to ensure it can’t be null. While late
is very convenient in tests, it’s probably not the best construct to use for null safety in general because the compiler can’t help as much and any errors will occur while the application is in use. For test cases the convenience is a big win, and if a variable happens to not be initialized the test case will fail.