Description
Dart SDK version: 2.19.2 (stable) (Tue Feb 7 18:37:17 2023 +0000) on "linux_x64"
UPDATE: implementing it as an extension function works as expected. Quite odd.
Hello,
I've implemented the usual Result<T, E>
type. In case you are unfamiliar with it, it is just a type that carries the result of a computation that could fail. You can think of it as an exception moved into data.
Anyway, I've defined it as such:
enum ResultType { ok, error }
class Result<T, E> {
final ResultType type;
const Result(this.type);
Result<T2, E> andThen<T2>(Result<T2, E> Function(T data) f) {
switch (type) {
case ResultType.ok:
return f((this as ResultOk<T>).value);
case ResultType.error:
return this as Result<T2, E>;
}
}
}
class ResultOk<T> extends Result<T, Never> {
final T value;
ResultOk(this.value) : super(ResultType.ok);
}
class ResultErr<E> extends Result<Never, E> {
final E error;
const ResultErr(this.error) : super(ResultType.error);
}
We can then write a quick test for it:
test('happy case', () {
final Result<int, String> ok = ResultOk(10);
final Result<String, String> res = ok.andThen((n) {
if (n % 2 == 0) {
return ResultOk(n.toString());
} else {
return const ResultErr("not even");
}
});
expect(res, isA<ResultOk>());
});
Everything will compile, but once we run it, it fails with this error message:
type '(int) => Result<String, String>' is not a subtype of type '(int) => Result<String, Never>' of 'f'
The simpler map
function, and similar, works as expected:
Result<T2, E> map<T2>(T2 Function(T) f) {
switch (type) {
case ResultType.ok:
return ResultOk(f(this as ResultOk<T>).value));
case ResultType.error:
return this as Result<T2, E>;
}
}
Interestingly enough, defining andThen
as a function works as expected:
Result<T2, E> andThen<T, T2, E>(
Result<T, E> r,
Result<T2, E> Function(T) f,
) {
switch (r.type) {
case ResultType.ok:
return f((r as ResultOk<T>).value);
case ResultType.error:
return r as Result<T2, E>;
}
}
test('happy case', () {
final Result<int, String> ok = ResultOk(10);
final Result<String, String> res = andThen(ok, (int n) {
if (n % 2 == 0) {
return ResultOk(n.toString());
} else {
return const ResultErr("not even");
}
});
expect(res, isA<ResultOk>());
});
Notice that this time n
in not properly inferred, hence we have to manually specify it, but at least this is caught by both analyzer and compiler.
Hope the issue is clear,
Thanks for your work and support!