6月4日、Go Blogで「On No syntactic support for error handling」と題した記事が公開された。この記事では、Go言語におけるエラーハンドリング構文の冗長性をめぐる長年の議論と、今後この課題に対して構文レベルの改良を当面見送るというGoチームの最終方針について詳しく紹介されている。
エラーハンドリング冗長性という古くて根強い不満
Goユーザーの間では、if err != nil { ... }
という判定がコードを埋め尽くし「本質的な処理を読みづらくする」という不満が長年続いてきた。API呼び出しが多いプログラムでは、とりわけその傾向が顕著だ。
x, err := call()
if err != nil {
// handle err
}
上記のようなパターンが大量に並ぶことで「ノイズが多い」と感じられるわけだ。例えば以下のコードのように。
func printSum(a, b string) error {
x, err := strconv.Atoi(a)
if err != nil {
return err
}
y, err := strconv.Atoi(b)
if err != nil {
return err
}
fmt.Println("result:", x+y)
return nil
}
10行のうち実質4行しか「本質的な処理」をしていない――そんな指摘が調査やアンケートで繰り返し浮上した。
これまでの三つの本格提案とその挫折
1. 2018年 check
/ handle
案
Russ Cox がまとめた Go 2 ドラフトでは、次のような構文により冗長性を削減する設計が示された。
func printSum(a, b string) error {
handle err { return err }
x := check strconv.Atoi(a)
y := check strconv.Atoi(b)
fmt.Println("result:", x+y)
return nil
}
包括的ではあったが複雑すぎるとして支持は得られなかった。
2. 2019年 try
案
check
を簡素化し、組み込み関数 try
へ置き換えた提案である。
func printSum(a, b string) error {
x := try(strconv.Atoi(a))
y := try(strconv.Atoi(b))
fmt.Println("result:", x+y)
return nil
}
try
はエラー時に呼び出し元へ即座に戻る制御フローを隠蔽する。可読性・デバッグ容易性の観点から大きな反発を招き、約900件のコメントの末に撤回された。
3. 2024年 ?
演算子案
Rust の ?
演算子を踏襲し、より直感的にエラー伝播を行う構文を導入する提案だった。
func printSum(a, b string) error {
x := strconv.Atoi(a) ?
y := strconv.Atoi(b) ?
fmt.Println("result:", x+y)
return nil
}
少数のユーザーテストでは意味を推測できたものの、様々な意見が殺到し、コンセンサスを形成できずに提案は閉鎖された。
なぜ結論に至らなかったのか
- 合意形成の難しさ
いずれの提案も「現行が良い」「別案が良い」「デバッグが困難になる」など利害が拮抗し、圧倒的な支持を得られなかった。 - Go の設計哲学
Goには「同じことを複数の方法で書けるようにしない」という設計原則があり、エラーハンドリングのために新たな専用構文を持ち込むことが、その原則に反すると見なされる。 - 実装コストと互換性
構文変更にはコンパイラ・ツールチェーン・既存コードの移行といった高コストが伴う。一方で IDE によるコード補完や折り畳み機能で冗長感を軽減できる余地もある。 - ユーザー温度差
初学者や他言語から来たばかりの開発者は冗長性を強く訴えるが、熟練の Go 開発者は現状で十分と感じる傾向がある。
今後の方針──「構文変更は当面行わない」
Go チームは「当面、エラーハンドリングの構文を変更する試みを停止する」と明言した。以下が原文の結論部分からの引用だ。
For the foreseeable future, the Go team will stop pursuing syntactic language changes
for error handling.
We will also close all open and incoming proposals that concern themselves primarily
with the syntax of error handling, without further investigation.
当面の間、Go チームはエラー処理に関する言語構文の変更を中止します。また、エラー処理の構文に主眼を置く、現在進行中および新規の提案はすべて、さらなる調査を行わずにクローズします。
今後は次の方向性が示唆されている。
- 標準ライブラリやツールの拡充によってエラーハンドリング支援を強化する
- IDE がエラー判定行を折り畳むなど、読みやすさの向上をツール側で図る
- 実務で有用な スタックトレース付与やエラー合成ユーティリティ の提供を検討する
こうした「言語外」の改善に注力することで、冗長性の実害を抑えつつ言語仕様の安定を維持するというわけだ。
まとめ
- Go におけるエラーハンドリング冗長性は長年の課題である。
- Go チームは
check/handle
→try
→?
と三度の大規模提案を試みたが、いずれも広範な合意に至らず撤回された。 - 構文変更にはメリットもあるが、デバッグ容易性や設計哲学、移行コストなどマイナス面も大きい。
- 当面は構文をいじらず、ライブラリやツールでの支援に軸足を置くという結論に落ち着いた。
Go のエラーハンドリング表現はしばらく現行のまま続く見通しだが、周辺ツール・ライブラリの成熟により実際の開発体験は今後も改善していくだろう。
詳細は[ On No ] syntactic support for error handling - The Go Programming Languageを参照していただきたい。