Some tasks take time, such as reading a file. A Future promises a later result or error. async permits await inside a function. await waits for that task without automatically creating parallel CPU work. Missing values and failed tasks are two different cases.
01Return a result later
loadName returns Future<String?>. Its result may be text or null. Future.delayed simulates a delay. A real app might read a file or database instead.
Future<String?> loadName() async {
await Future<void>.delayed(const Duration(milliseconds: 100));
return null;
}
Future<void> main() async {
try {
final name = await loadName();
print(name ?? 'No vehicle yet');
} catch (error) {
print('Loading failed: $error');
}
}
Run / check
dart run async.dart02Use await and ??
await loadName() yields the eventual value. ?? then handles only null. A thrown exception instead skips normal result processing and reaches catch.
03Handle errors visibly
Try changing loadName to throw StateError("Cannot load"). The error message shows the other path. An interface will later distinguish loading, success, empty data and failure. A missing name must not silently become a successful load containing invented data.
After a short delay: No vehicle yet
Your exercise
Return Family car instead of null. Then remove await and observe the result type.
Show the solution and explanation
With await you receive String?. Without await you receive Future<String?>. That is the unfinished task rather than the completed name. Restore await before processing the name.
Project context and sources
The example is simplified for learning. The linked source version shows its use in the project and the checks applied there.