Resultライブラリを使うべきか
あまり知られていないと思うが、実は、package:async
にResultライブラリが存在する。
https://pub.dartlang.org/documentation/async/latest/async/Result-class.html
Result
Resultのソースコードに端的に表現されている。やっていることはこれだけ。
/// Creates a `Result` with the result of calling [computation]. /// /// This generates either a [ValueResult] with the value returned by /// calling `computation`, or an [ErrorResult] with an error thrown by /// the call. factory Result(T computation()) { try { return new ValueResult<T>(computation()); } catch (e, s) { return new ErrorResult(e, s); } }
計算結果、または計算過程でのエラーをキャッチしてResultオブジェクトでくるむ。
final result = Result(() => someAction());
あとは、通常の制御構文を使用する。
if (result.isValue) { final computationResultValue = result.asValue.value; // proceed. } else { result.asError.handle((error) { // error handling. }); }
ExceptionやErrorのハンドリングを網羅しているかどうかを静的に検査できるわけではない。 また、try catchにおけるアンチパターンと同様に、計算を雑にResultでくるんで回復不能なエラーまで握りつぶしてしまわないように注意。
非同期処理をキャッチする
Result.capture
でFutureをcatchできる。
final result = await Result.capture(someFutureAction());
Result.captureAll
でFutureのIterableを、Result.captureStream
でStream
をcaptureできる。
標準のtry - catch - finallyとの使い分け
ほとんどの場合は、標準のtry - catch - finallyを使えばよいだろう。
- Dartの
try
は優秀で、async await
を組み合わせれば同期処理と非同期処理が混在していてもcatchしてくれる。 - プログラマーは
try
での処理に慣れているため、学習コストがない。 Result
は標準ライブラリに含まれていない。
Result
を使えば、以下のメリットがあるだろう。
- コードレビュー時に、
try
よりもResult
のほうがエラーハンドリングの不備が見逃されづらくなる。 - エラーハンドリングのタイミングを遅延させるほうが便利な、特殊な状況がまれにある。
よって、少なくとも、パッケージを作成するときは、パッケージ利用者にResultの使用を強制しないようにデザインするとよい。つまり、ライブラリの公開インターフェースにResultを使用しない。
プライベートなアプリ開発においては、Result
を使用する基準は、開発チームが議論して決めたら良い。
背景に関してのメモ
Dart言語は、評価が定まっていない仕様を軽率に採用してあとから取り除くこともできず、結果として言語仕様やコアなエコシステムが乱雑になる事態を警戒してきたことが観察できる。たとえ、Kotlin、Swift、ScalaやJavaScriptなどの他の言語で良いとされて導入されているアイデアであっても、言語仕様や標準ライブラリへの追加には、極めて慎重で注意深い態度を示してきた。
言語マニアからまれに批判される、パターンマッチングが無いことなどについても、長い議論の末に、極めて意図的に、あえて非採用、またはペンディング扱いになっていることがGitHub Issueやカンファレンス動画などからうかがえる。
そして、Dart 1にはそのような言語仕様や標準ライブラリのマイナーな改善よりもはるかに優先順位が高い事項がたくさんあったが、悲しいことに、その独自の哲学とビジョンはあまり理解されることはなく、推進力を得ることができなかった。
方針変更したDart 2では大きな仕事が一段落したようで、比較的マイナーな事項に関する進化を進めているので、気になる人はdartlang/languageリポジトリをwatchしたらいいんじゃないかと思う。