Dart 3 Records and Patterns in Flutter: solved exercise
Dart 3 Records and Patterns in Flutter: solved exercise
Dart 3 introduced three major language features: records (anonymous structs with static typing), patterns (destructuring and pattern matching), and sealed classes (closed hierarchies that enable exhaustiveness checking). Together they transform how state and business logic are modeled in Flutter.
Problem statement
Implement a mini-app that demonstrates all three features:
- Records: function that returns a record with name, price, and stock.
- Pattern matching with switch expression:
area()function accepting different shapes. - Sealed classes:
LoadState<T>to model async state (Loading,Success,Failure). - List & map patterns: destructuring of lists and maps.
- Display all examples in a screen with a
ListViewofCardwidgets.
Dependencies
Dart 3 only — already included in Flutter 3.10+. No extra dependencies.
Full solution
Key concepts
| Concept | Detail |
|---|---|
(A, B) | Positional record; access with $1, $2 or destructuring (var a, var b) = rec |
({String name, int age}) | Named record; access with .name, .age |
sealed class | Closed class: only subclasses in the same file. Enables exhaustiveness in switch |
switch expression | Expression (not statement) that returns a value; compiler requires all cases to be covered with sealed |
:var field | Named object pattern: extracts field without repeating the name |
[first, ..., last] | List rest pattern: captures first and last element, ignores the middle |
{'key': var v} | Map pattern: extracts the value at key 'key' |
Common mistakes
- Non-exhaustive
switch: with sealed classes, the compiler emits a warning if any subtype is missing. Only add a_case if there is a genuinely valid default. - Records vs classes: records are immutable and have no methods. For business logic, a class is still better. Records shine for multiple return values and temporary data.
$1vs.fieldName: positional records use$1,$2…; named records use.fieldName. Mixing them causes a compile error.- Flutter < 3.10: Dart 3 requires Flutter 3.10+. Verify with
flutter --version.
Practical application
- Multiple return values:
(String, int) parseVersion(String v)avoids creating wrapper classes. - Async state:
LoadState<T>sealed is a very clean pattern that replaces multiple booleans (isLoading,hasError). - Pattern matching in Navigator:
switch (route)with sealed classes for type-safe routing. - Riverpod + sealed: combined with
@riverpod,AsyncValueuses the same pattern internally.
Recommended next exercises
Guided practice and next step
- More Flutter exercises
- C exercises to strengthen fundamentals
- Programming in C in 100 Solved Exercises
- View on Amazon (included in Kindle Unlimited)
FAQ
Do records replace classes in Dart 3?
No. Records are for temporary data, multiple return values, and simple composition. Classes remain better when you need methods, inheritance, custom equality (though records have automatic structural equality), or complex JSON serialization.
What is the difference between a switch statement and a switch expression?
The switch expression (with =>) returns a value and is more concise. The switch statement (with { case: break; }) executes code. With Dart 3, the expression is preferred for mapping values; the statement for executing side effects.
Are sealed classes like enums?
They are complementary. Enums are for simple constant value sets. Sealed classes are for type hierarchies where each subtype can have its own fields. LoadState<T> with Success(data) and Failure(message) would not be possible with an enum.