Elegant error handling in Dart like Scala's `Try`
Solution 1
If you are OK with using Future
what's wrong with this advice: Using Future.sync() to wrap your code? The code will look like this:
void main() {
var f = Future.sync(() {AuthUser("email", "token", "username", "bio", "img"); });
f.then((v) => print("Value: " + v.toString())).catchError((e) => print("Failure: " +e.toString()));
}
The main trick is that Future.sync
effectively enables lazy evaluation of the parameter but you have to pass your parameter wrapped in a function. This is actually the same trick Scala compiler does for Try
(i.e. for call-by-name parameters) but takes adding a few brackets around.
Solution 2
If you only want the basic functionality of returning either type based on whether an exception occurred or not then you can easily create a utility class such as below.
Otherwise I recommend @SergGr's answer about using Future.sync
since it gives you more monadic like pipeline.
void main() {
Try<Error, void> result = Try.it(() => Validate.isEmail("test-example.com"));
if (result is Success) {
print("Good");
} else if (result is Failure) {
print("Error: " + result.exception().toString());
}
}
typedef TryExec<V> = V Function();
abstract class Try<E extends Error, V> {
static Try<E, V> it<E extends Error, V>(TryExec<V> fn) {
try {
return Try.success(fn());
} catch (e) {
return Try.failure(e);
}
}
static Try<E, V> failure<E extends Error, V>(Error e) {
return new Failure(e);
}
static Try<E, V> success<E extends Error, V>(V v) {
return new Success(v);
}
}
class Failure<E extends Error, V> extends Try<E, V> {
final E _e;
Failure(this._e);
E exception() => _e;
}
class Success<E extends Error, V> extends Try<E, V> {
final V _v;
Success(this._v);
V value() => _v;
}
Ukonn Ra
Updated on December 07, 2022Comments
-
Ukonn Ra over 1 year
A data class in Dart:
import 'package:validate/validate.dart'; class AuthUser { final String email, token, username, bio, image; AuthUser(this.email, this.token, this.username, this.bio, this.image) { Validate.isEmail(this.email); } @override String toString() { return 'AuthUser{email: $email, token: $token, username: $username, bio: $bio, image: $image}'; } }
where
Validate.isEmail
will throws an Error when failed to match:static void matchesPattern(String input, RegExp pattern,[String message = DEFAULT_MATCHES_PATTERN_EX]) { if (pattern.hasMatch(input) == false) { throw new ArgumentError(message); } } static void isEmail(String input,[String message = DEFAULT_MATCHES_PATTERN_EX]) { matchesPattern(input,new RegExp(PATTERN_EMAIL),message); }
Now I want to use an elegant way to new this class. When using Scala, I can use
Try(new AuthUser(...))
and patten-matching it.And in Dart, first I tried RxDart,
void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { Observable.just(AuthUser("email", "token", "username", "bio", "img")) .doOnError((e, s) => print("oh no")) .listen((e) => print(e.toString())); }); }
Not work, the test failed for the error(which means RxDart doesn't catch errors at all!!!)
And I want to try Future, failed also.
And I want to use dartz, but I am worried because there is just one maintainer...
Any advice?
-
JRomero over 5 yearsRxDart isn't catching the exception because the exception is being thrown before it's part of the
Observable
. To elaborate, your code is equivalent tofinal user = AuthUser(); Observable.just(user);
. As you can now see the exception is when creating the user. -
Rémi Rousselet over 5 yearsThere is no pattern matching in dart
-
Ukonn Ra over 5 years@RémiRousselet I know, I just need a solution to try/catch exception elegantly
-
Ukonn Ra over 5 years@JRomero So any advice?
-
Chris Reynolds over 5 yearsMy immediate reaction is Just Don’t. The language has a specific way of trapping errors and grafting on your preferred method from another language is probably not best practice. However that is a personal opinion.
-
-
Chris Reynolds over 5 yearsMy immediate reaction is Just Don’t. The language has a specific way of trapping errors and grafting on your preferred method from another language is probably not best practice. However that is a personal opinion.