With Dart development, the issue of compliance versus guidelines is coming up for me frequently as I am learning about null safety.
This morning, I read through a section of Effective Dart that solved a problem for me with null variables.
The relevant section is below.
AVOID late variables if you need to check whether they are initialized.
Dart offers no way to tell if a late variable has been initialized or assigned to. If you access it, it either immediately runs the initializer (if it has one) or throws an exception. Sometimes you have some state that’s lazily initialized where late might be a good fit, but you also need to be able to tell if the initialization has happened yet.
Although you could detect initialization by storing the state in a late variable and having a separate boolean field that tracks whether the variable has been set, that’s redundant because Dart internally maintains the initialized status of the late variable. Instead, it’s usually clearer to make the variable non-late and nullable. Then you can see if the variable has been initialized by checking for null.
Of course, if null is a valid initialized value for the variable, then it probably does make sense to have a separate boolean field.
CONSIDER copying a nullable field to a local variable to enable type promotion.
Checking that a nullable variable is not equal to null promotes the variable to a non-nullable type. That lets you access members on the variable and pass it to functions expecting a non-nullable type. Unfortunately, promotion is only sound for local variables and parameters, so fields and top-level variables aren’t promoted.
One pattern to work around this is to copy the field’s value to a local variable. Null checks on that variable do promote, so you can safely treat it as non-nullable.
class UploadException {
final Response? response;
UploadException([this.response]);
@override
String toString() {
var response = this.response;
if (response != null) {
return 'Could not complete upload to ${response.url} '
'(error code ${response.errorCode}): ${response.reason}.';
}
return 'Could not upload (no response).';
}
}
There’s a nice convention of providing good and bad examples. The good examples are green. The bad examples are red. 