In code reviews, I often see a construction like this:
enum Some { option1, option2 }
final someCondition = Some.option2;
void main() {
late final String x;
switch (someCondition) {
case Some.option1:
x = 'a';
break;
case Some.option2:
x = 'b';
break;
}
print(x);
}
Take a look at the line late final String x
. At first glance, there's nothing wrong with it: we don't initialize x
immediately, but at some point later, so late
modifier seems to be a good fit here, right?
Wrong. Dart compiler is smart enough to understand that there's no way for x
to be unitialized when it's called at print(x)
. So you can just omit late
modifier:
enum Some { option1, option2 }
final someCondition = Some.option2;
void main() {
final String x;
switch (someCondition) {
case Some.option1:
x = 'a';
break;
case Some.option2:
x = 'b';
break;
}
print(x);
}
And it's not just about being concise. It actually guards you against making an error. Take a look at the following snippet:
enum Some { option1, option2 }
final someCondition = Some.option2;
void main() {
late final String x;
switch (someCondition) {
case Some.option1:
x = 'a';
break;
}
print(x);
}
Do you see an error here? We don't process all the possible cases and, since in our case, someCondition == Some.option2
we will get a runtime error:
Uncaught Error: LateInitializationError: Local 'x' has not been initialized.
What if we remove late
modifier?
enum Some { option1, option2 }
final someCondition = Some.option2;
void main() {
final String x;
switch (someCondition) {
case Some.option1:
x = 'a';
break;
}
print(x);
}
Now, we can't even run the code, since we get a compile-time error:
Error: Final variable 'x' must be assigned before it can be used.
print(x);
^
Error: Compilation failed.
It can help you in other cases as well, such as if..else
or try..catch
blocks.
So pay attention to this small detail and stay safe!