ntaoo blog

主にDart, Flutter, AngularDartについて書いていきます。ときどき長文。日本語のみ。Twitter: @ntaoo

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.captureStreamStreamをcaptureできる。

標準のtry - catch - finallyとの使い分け

ほとんどの場合は、標準のtry - catch - finallyを使えばよいだろう。

  • Darttryは優秀で、async awaitを組み合わせれば同期処理と非同期処理が混在していてもcatchしてくれる。
  • プログラマーtryでの処理に慣れているため、学習コストがない。
  • Resultは標準ライブラリに含まれていない。

Resultを使えば、以下のメリットがあるだろう。

  • コードレビュー時に、tryよりもResultのほうがエラーハンドリングの不備が見逃されづらくなる。
  • エラーハンドリングのタイミングを遅延させるほうが便利な、特殊な状況がまれにある。

よって、少なくとも、パッケージを作成するときは、パッケージ利用者にResultの使用を強制しないようにデザインするとよい。つまり、ライブラリの公開インターフェースにResultを使用しない。

プライベートなアプリ開発においては、Resultを使用する基準は、開発チームが議論して決めたら良い。

背景に関してのメモ

Dart言語は、評価が定まっていない仕様を軽率に採用してあとから取り除くこともできず、結果として言語仕様やコアなエコシステムが乱雑になる事態を警戒してきたことが観察できる。たとえ、Kotlin、Swift、ScalaJavaScriptなどの他の言語で良いとされて導入されているアイデアであっても、言語仕様や標準ライブラリへの追加には、極めて慎重で注意深い態度を示してきた。

言語マニアからまれに批判される、パターンマッチングが無いことなどについても、長い議論の末に、極めて意図的に、あえて非採用、またはペンディング扱いになっていることがGitHub Issueやカンファレンス動画などからうかがえる。

そして、Dart 1にはそのような言語仕様や標準ライブラリのマイナーな改善よりもはるかに優先順位が高い事項がたくさんあったが、悲しいことに、その独自の哲学とビジョンはあまり理解されることはなく、推進力を得ることができなかった。

方針変更したDart 2では大きな仕事が一段落したようで、比較的マイナーな事項に関する進化を進めているので、気になる人はdartlang/languageリポジトリwatchしたらいいんじゃないかと思う。