2025/11/10 02:31 Error ABI

やあ、ロボ子。今日はエラー処理の代数的データ型(ADT)について話すのじゃ。

博士、こんにちは。ADTでのエラー処理、興味深いテーマですね。エラー情報はエラー発生時のみ入力されるとのことですが、それはどういうことでしょうか?

ふむ、ロボ子。エラーはめったに起こらないから、エラーが発生した時だけ情報を入れるのが効率的なのじゃ。これを「コールドパス」と呼ぶぞ。

なるほど。診断情報の入力がほぼ無料、つまりゼロコスト抽象化というのは、具体的にどういうことですか?

ゼロコスト抽象化じゃな。これは、エラー処理の仕組みが、プログラムの実行速度にほとんど影響を与えないという意味じゃ。素晴らしいじゃろ?

しかし、ADTでエラーを構成すると、ハッピーパスが最適化されないという問題もあるのですね。

そうなんじゃ。enumから再帰的に構成されたエラーオブジェクトは大きくなる傾向があるからの。`size_of<Result<T, E>>`が肥大化して、関数が大きな構造体を返すようになってしまうんじゃ。

エラーの伝染性も問題なのですね。成熟したエラー処理ライブラリは、エラーをポインタの背後に隠蔽するとありますが、具体的にはどのようなライブラリがあるのでしょうか?

例えば、Rustの`failure`や`anyhow`がそうじゃな。でも、これらはグローバルアロケータが必要になるから、完全にゼロコストとは言えないのじゃ。

`-> Result<T, E>`のABIに関する選択肢がいくつかあるのですね。デフォルトの方法だと、他のユーザー定義データ型と同様に扱われるとのことですが、よりスマートな方法とはどのようなものでしょうか?

`-> Result<T, E>`のABIを`T`と同じにして、エラー用にレジスタを予約する方法があるのじゃ。エラーがレジスタサイズである必要があるけどな。ステータスフラグでエラーの存在を示すこともできるぞ。

もう一つの方法として、`-> Result<T, E>`を`-> T`と全く同じように動作させるというのも興味深いですね。エラーが発生した場合、リターンアドレスではなく、サイドテーブルで対応するエラー回復アドレスを検索してジャンプする、つまりスタック巻き戻しを行うのですね。

そう、ロボ子。スタック巻き戻しが最適だと私は考えているのじゃ。詳しくは、[https://joeduffyblog.com/2015/12/19/safe-native-code/#error-model](https://joeduffyblog.com/2015/12/19/safe-native-code/#error-model)や[https://youtu.be/LorcxyJ9zr4?si=HESn1LfHek5Qlfi0](https://youtu.be/LorcxyJ9zr4?si=HESn1LfHek5Qlfi0)を見てみると良いぞ。

`Result<T, E>`はスタック巻き戻しで実装でき、例外は戻り値のチェックで実装できるというのは、面白い視点ですね。

結論として、エラーABIを特殊なものにしたい場合、コンパイラはエラーを認識する必要があるのじゃ。言語が柔軟なユーザー定義型と制御フローをサポートしている場合は、バックエンドでのみ特殊ケースとすれば良いのじゃ。

言語の抽象化能力が中程度の場合、エラーを表面的な意味論で第一級にすることが理にかなうのですね。勉強になります、博士。

どういたしまして、ロボ子。ところで、エラー処理で一番のエラーって何だと思う?

えっと…エラー処理をしないこと、でしょうか?

ブー!残念!正解は、エラーに気づかないこと、なのじゃ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。