Swiftのエラー4分類が素晴らしすぎるのでみんなに知ってほしい

  • 590
    Like
  • 11
    Comment

これは Swift Tweets の発表をまとめたものです(次回開催はこちら)。イベントのスポンサーとして Qiita に許可をいただいた上で、このような形(ツイートの引用)で投稿しています。

追記: 読みづらいという意見が多いようだったので試験的に Markdown 版も作りました。ただ、個人的には構造化されてないドキュメントをこの形式で読むのは辛く、まだツイートの引用の形の方が読みやすいように思います。 Qiita の投稿に最適な構成に書き直して投稿すれば読みやすいと思いますが、その時間を確保することができないですし、この投稿はあくまでも Swift Tweets での発表を保存する目的のものだということでご容赦下さい。詳しくはコメントしました。


↑に関する訂正を含む補足の追記

追記(2017-01-18)

id:sawat IllegalArgumentException が Logic failure じゃない場面なんてそんなに多くない気がするが…。

はてブでこのようなコメントをいただいて考えていたのですが、たしかにその通りなように思います。

Logic failure かそうでないかの境目は、エラーが発生したときにそれをハンドリングして何らかの処理を実行することがあるかどうかですが( Array の index out of bounds を処理することが滅多にないので Logic failure としたのと同じように)、 前提条件が明確な IllegalArgumentException (引数に渡された不正な値が原因のエラー)であっても、それをハンドリングする必要があるようなオペレーションは下記のケースを除いてほとんど思い付きませんでした。

Simple domain error となるのは次のようなケースです( removeLast メソッド等は引数が不正なわけではないですが、第一引数にオブジェクト自身を渡す関数と読みかえれば引数の不正と同じ話です)。

  • 変換(例: parseInt, JSON のデコード等)
  • 値の不在(例: pop, Iteratornext 等)
  • 計算(例: ゼロ除算(単位ベクトルや逆行列の演算)、負の数の平方根)
  • 数を引数にとる処理(例: 配列の生成)

値の変換はプログラムの外から来た値がインプットとなる場合が多いので、コードレベルで不正値を防ぐことができないケースが多く、エラーをハンドリングしたいです。コレクションに対する操作も、 DB から取得するなど外部から来たものを操作することが多く同様です。

計算や数を引数にとる処理は、オペランドや引数が計算の結果として導かれた結果、簡単に値が範囲外になってしまいます。 sqrt(a - b)a - b が負であるような場合に、事前チェックが必要なのであれば、それは Logic failure ではなく Simple domain error であるべきです。コレクションのケースも同様に、他のオペレーションの結果としてコレクションを得た場合には、 pop する前に空でないことなどのチェックが必要となります。

これらに共通なのは、引数に渡される値をコードレベルでコントロールできない(コントロールするのが難しい)ことです。そのため、引数に不正な値が渡されるケースがコードの誤りとは限らず、 Logic failure ではなく Simple domain error として扱いたいわけです。

しかし、不正引数で引き起こされる他の多くのケースはエラーは捕まえてもどうしようもないことが多いように思います( MessageDigestgetInstance に未知のアルゴリズムを表す文字列が渡された場合など)。なので、

前提条件が明確なエラーの多くはSimple domain errorとして扱うのが適切です。

というのは 誤り だと言えそうです。訂正します。

ただ、 Simple domain error を発生させるような処理は利用頻度が高く、それらが安全にハンドリングできないことによるストレスは大きいとは思います。 Java には Simple domain error を安全かつ快適に扱う良い方法がなく( try-catch は大がかりすぎますし、 null を返しても null チェックを無視できてしまうので安全でありません。しかも、 null はネストできないので、たとえば Iteratornextnull でエラーを表すと、次の値が存在しないのか、次の値が null なのかを区別できません。)、 Simple domain error であるべきエラーが Logic failure として扱われているという点自体は間違いではないので、全体的な論旨はおかしくないと思います。