Chapter 1 · Practice 3 of 5
Use late only when initialization order is truly under your control
From Dart and null safety
Why it matters
The late modifier tells Dart to enforce a variable's constraints at runtime instead of at compile time. The Dart docs warn that any use of a late field could fail, and there is nothing visible at the use site to tell you. Reading a late field before it is assigned throws, and assigning a late final field twice also throws.
late is fine for:
- a controller created in
initState()and used inbuild(), where Flutter calls them in a known order, - an expensive value you want computed lazily on first read.
It is a poor fix for "I do not know when this gets set". In that case, use a nullable type and handle the missing case, or pass the value in through the constructor.
Do
- Initialize
latecontrollers ininitState()and dispose them indispose()
Avoid
- Marking a field
latebecause a network call will fill it in "at some point"
Example
class _SearchState extends State<Search> {
late final TextEditingController _query;
@override
void initState() {
super.initState();
_query = TextEditingController();
}
@override
void dispose() {
_query.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => TextField(controller: _query);
}