Dart
Result pattern
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.
Exercise 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.
Show example 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);
}
}
Test yourself
-
What is the advantage of the Result pattern?
- Ignores errors
- Makes errors type-safe
- Runs faster
- Removes Exception
Show answer
Makes errors type-safe — the Result pattern represents each error case with a type.
-
Access the Success value
switch (result) { case Success(:final value): print(____); }
Show answer
switch (result) { case Success(:final value): print(value); }
-
Result pattern parts
- Success<T>
- Success case
- Failure<T>
- Failure case
- sealed class
- Closed hierarchy
- switch
- Pattern matching
Next lesson: Async errors