Open
Description
Playground: https://dartpad.dev/cb41699ff72a41cb9412ef48f47cf824.
I've really enjoyed Dart's 3 class modifiers and pattern matching.
I'm trying to implement a Result<T, E>
type, similar to Rust's std::result
:
sealed class Result<T, E> {
const Result();
const factory Result.value(T value) = ValueResult._;
const factory Result.error(E error) = ErrorResult._;
}
final class ValueResult<T, E> extends Result<T, E> {
final T value;
const ValueResult._(this.value);
}
final class ErrorResult<T, E> extends Result<T, E> {
final E error;
const ErrorResult._(this.error);
}
As you can see in my playground, it works! It's just a bit more complicated than I'd expect for a sealed type with only two sub-types (I can see how the implementation as-is works for traditional enum-like types). Here are the individual test cases I wrote:
// Doesn't work, the "else" case doesn't promote willSucceed to ErrorResult, despite the fact that it must be?
if (willSucceed is ValueResult<int, String>) {
print('value: ${willSucceed.value}');
} else {
print('error: ${willSucceed.error}');
}
// Similar to above.
if (willSucceed case ValueResult(value: final value)) {
print('value: $value');
} else {
print('error: ${willSucceed.error}');
}
// Works, but is the most typing.
switch (willSucceed) {
case final ValueResult<int, String> result:
print('value: ${result.value}');
case final ErrorResult<int, String> result:
print('error: ${result.error}');
}
// Works, and is probably what I'd use.
switch (willSucceed) {
case ValueResult(: final value):
print('value: $value');
case ErrorResult(: final error):
print('error: $error');
}
Maybe there is a better way to do this I don't know about or this can serve as inspiration for type inference improvements.
Thanks!