歴史的な提案:check/handleとtry

2018年のcheck/handle提案

Goチームによる最初の明確な試みは2018年にさかのぼります。Russ Coxが当時Go 2の取り組みの一部として問題を正式に記述しました。彼は、Marcel van Lohuizenによるドラフト設計に基づく可能な解決策を概略しました。

この設計はcheckhandleメカニズムに基づいており、かなり包括的でした。ドラフトには、他の言語で採用されているアプローチとの比較を含む、代替ソリューションの詳細な分析が含まれています。

// 提案されたcheck/handleメカニズムを使用したprintSum実装
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
}

この提案では:

  • handle err { ... }でエラー処理ロジックを定義
  • checkキーワードでエラーを自動チェックし、エラー時にはhandleブロックを実行
  • コードがより簡潔になり、ビジネスロジックが明確になる

しかし、このcheckhandleアプローチは複雑すぎると判断されました。

2019年のtry提案

2018年の提案から約1年後の2019年、チームは大幅に簡素化された、今では悪名高いtry提案でフォローアップしました。これはcheckhandleのアイデアに基づいていましたが、check疑似キーワードはtry組み込み関数になり、handle部分は省略されました。

// 提案されたtryメカニズムを使用したprintSum実装
func printSum(a, b string) error {
    // エラーを返す前に拡張するためにdefer文を使用
    x := try(strconv.Atoi(a))
    y := try(strconv.Atoi(b))
    fmt.Println("result:", x + y)
    return nil
}

try組み込みの影響を探るために、既存のエラーハンドリングコードをtryを使用して書き換える簡単なツール(tryhard)を作成しました。この提案は激しく議論され、GitHubのissueに900近いコメントが寄せられました。

try提案の問題点と結果

しかし、tryはエラーの場合に外側の関数から戻ることで制御フローに影響を与え、潜在的に深くネストした式からそれを行うため、この制御フローが見えにくくなりました。これにより、提案は多くの人にとって受け入れがたいものとなり、この提案への大きな投資にもかかわらず、この取り組みも放棄することを決定しました。

振り返ってみると、新しいキーワードを導入する方が良かったかもしれません。これは、go.modファイルとファイル固有のディレクティブを通じて言語バージョンをきめ細かく制御できるようになった今では可能なことです。tryの使用を代入と文に制限することで、他の懸念の一部を軽減できたかもしれません。

影響と反省

try提案の反響は、Russ Coxによる一連のブログ投稿「Thinking about the Go Proposal Process」を含む多くの内省につながりました。一つの結論は、コミュニティのフィードバックの余地がほとんどない、ほぼ完全に練られた提案と「脅威的な」実装タイムラインを提示することで、より良い結果の可能性を減らしてしまったかもしれないということでした。

しかし、この場合の可能な処理と通信の失敗に関係なく、提案に対するユーザーの感情は非常に強く反対でした。