Goのerrorがスタックトレースを含まない理由

Twitterでこんな記事を見かけたので。

zenn.dev

ジェネリクスの件もそうですが、Goの言語設計は現実主義なのになにか特別なポリシーによるものだと宗教化されてしまって、ファンには勝手に崇拝されてアンチにはディスられがちだなーと感じます。

Goのエラー処理を改善する実験プロジェクトxerrorsがGo本体のerrorsにマージされた時、 errors.New()スタックトレースを取得していました。しかしGo 1.13がリリースされる前に削除されました。

削除された理由の1つは、今までの errors.New() のパフォーマンスに依存していたコードの速度が低下しアロケーションが増えることです。

github.com

しかし、これが理由だと今まで思ってたのですが、実際にはもう1つより重要な理由がありました。エラーのフォーマットです。エラーに複数のフォーマットを持たせようという提案が、経験不足を理由に延期されたのです。

Go 1.13 のステータスを説明するコメント

複数の異なるフォーマットの扱いが仕様化されてないということは、スタックトレースの情報をエラーにつけてもそれを表示する手段がありません。すでに使われている表示手段は後方互換性のために変えられないので、スタックトレース付きでエラー表示をするための追加仕様が必要なのです。表示する手段が存在しないのに、単に遅くてアロケーションが多いだけのスタックトレース付きエラーを標準ライブラリに入れる必要はありません。

ということで、Go標準でスタックトレース情報付きのエラーを提供することは、エラーのフォーマットを拡張する提案の中に含まれる形で現在もドラフトになっています。

go.googlesource.com

ということで、Goの開発者やGooglerが何か特別なポリシーや宗教上の理由でスタックトレースをエラーに付けていないわけではありません。単に影響範囲がデカい言語仕様だとかコアライブラリの新規APIに対する仕様追加に極めて慎重で時間をかけてるだけでした。エラーにスタックトレースをつけるライブラリを使っても、Go Wayに違反して善きGopherになれなくなるなんて事は全くないので、安心して使えば良いと思います。

その際は他のライブラリの選定の時と同じく、信頼性のあるソフトウェアを参考にしつつ、依存ライブラリの数やシンプルさ、将来Goの標準ライブラリに追加された時に移行しやすそうかなどを考えて選べば良いでしょう。 特に1つのライブラリをお勧めできるほどGoのエコシステムに詳しいわけではありませんが一例として、CockroachDBは(名前が最悪なのはともかく)Goで書かれた信頼性の高いソフトウェアなので、 github.com/cockroachdb/errors は参考になるかもしれませんし、分散システムを作るのでなければ複雑すぎるかもしれません。

追記

上で紹介したドラフト以外にも、エラーにスタックトレースをつけるための複数の提案がTwitter上で紹介されていました。

github.com

github.com

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。