Result型
例外を使わず、常に結果を返し、結果には成功/失敗と値の2つが返ってくるべきというもの。
当初のC言語などの高級言語では、結果は1つしか返せず、スカラー値しか返せなかった。
これは、数学のように書けるように、y = f(x) の形式を採用したため。
(返り値をそのまま使うことができるので g(f(x)) のような書き方ができるのが利点とされる。)
同様に、多くの言語で返り値として1つの値しか返せない形になっている。
この場合、返り値に何を返すのかが問題となり、以下のような選択肢になっていた。
値そのものを返す。失敗時には特定の値を返す。(例えば-1)
成功失敗などの情報を返す。出力は引数側に書く。
最近では、この方式に問題があるとして、データ構造を出力として返すことができるようになってきている。
このような成功/失敗の伝達方式だと、何かの関数を呼ぶたびにエラートラップを書く必要が出てきて、とても邪魔になった。 また、エラーの取り扱いは製作者によってばらばらでまったく統一性がなかった。
これで、何らかのトラブル(期待しない値の受け取り、0割りなどの計算エラー、I/Oエラーなど)が起きた時に、ルーチンの上層に例外のトラップを置くだけでよくなった。
一方、例外では以下のような問題が発生するようになった。
いつどこから例外が発生するのか予期できない。
予期できるように関数に宣言を書く方式はあまりに難しすぎて誰も実践できなかった。(エラートラップ問題と同じ)
宣言を全部丸呑みするような宣言や catch を書くので意味を失った。(全部 throws Exception と書くことになってしまう)
例外を想定していないルーチンで後始末などの処理が漏れることがある。
例外を握りつぶす悪いコーディングが氾濫した。
何でもかんでも例外をトラップしてログなどを吐く悪いコーディングが氾濫した。(これではエラートラップの削減の目的から逸脱してしまう)
このような問題から Result 型を言語標準として持つ考えが現れてきた。
Result 型は、成功/失敗のフラグと、その状況にふさわしい値を持つ。
極めて簡単なエラートラップ構文を持つ。(Rust では unwrap が最小になる。)
標準化されているので、人により異なる手法にならない。
これで、本当に必要ならエラートラップで対処して、そうでないなら簡単なキーワードで無視できるようになった。
無視したのにエラーが出たなら、プロセスは異常終了する。
Result 型を持っていないにもかかわらず、Result 型を模倣しようとする場合にはかなり注意が必要。
サードパーティのライブラリは相変わらず例外を飛ばしてくることがある。
言語標準の作法と異なるため、そこでアンマッチを起こすことが多々ある。