Result pattern
- Dart course
- Intermediate
- Lesson 103/116
- 5 min
Learn functional error handling with the Result pattern.
Result pattern
Returning errors as values instead of throwing exceptions is a functional approach. This is called the Result pattern.
In Dart you typically define a sealed class Result<T>: Success<T>(T value) and Failure<T>(String error). The caller splits the value with pattern matching.
This handles errors in a type-safe way; a forgotten error case becomes a compile error.
A Result pattern example
A typical divide function: Result<int> divide(int a, int b). If b is zero it returns Failure('division by zero'), otherwise Success(a ~/ b).
The caller: switch (result) { case Success(:final value): print(value); case Failure(:final error): print(error); }.
Thanks to sealed the compiler checks every case; adding a new subclass warns all switches.
Practice Divide with Result
Define sealed class Result<T> {}. Add class Success<T> extends Result<T> (final T value + constructor) and class Failure<T> extends Result<T> (final String error + constructor). Write Result<int> divide(int a, int b): if b is 0 return Failure('division by zero'), else Success(a ~/ b). In main call divide(10, 0) and split with switch: print value on Success, error on Failure.
Starter code
// Define the Result, Success, Failure classes
// Write the divide function
void main() {
// call divide(10, 0), split with switch
}Sample solution
sealed class Result<T> {}
class Success<T> extends Result<T> {
final T value;
Success(this.value);
}
class Failure<T> extends Result<T> {
final String error;
Failure(this.error);
}
Result<int> divide(int a, int b) {
if (b == 0) return Failure('division by zero');
return Success(a ~/ b);
}
void main() {
final r = divide(10, 0);
switch (r) {
case Success(:final value):
print(value);
case Failure(:final error):
print(error);
}
}Expected output
division by zero
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is the advantage of the Result pattern?
- Ignores errors
- Makes errors type-safe Correct answer
- Runs faster
- Removes Exception
Explanation: the Result pattern represents each error case with a type.
2 Access the Success value
switch (result) { case Success(:final value): print(____); }
switch (result) { case Success(:final value): print(value); }
Explanation: the Success pattern binds value.
3 Result pattern parts
| Term | Meaning |
|---|---|
Success<T> |
Success case |
Failure<T> |
Failure case |
sealed class |
Closed hierarchy |
switch |
Pattern matching |