giftee Tech Blog

ギフティの開発を支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信しています。

Go Conference 2024 レポート 『Goにconst型修飾を期待しなくてよい理由』

こんにちは、ギフティでエンジニアをしている @memetics10 です。

6/8 (土) に開催された Go Conference 2024 に参加してきたので、その中で印象に残ったセッションについて紹介しようと思います。

セッション 『Goにconst型修飾を期待しなくてよい理由』

Go Conference 2024 ではいくつもの素晴らしいセッションがありましたが、その中でも印象的だったのは Kazuhiro Sakurayama さんの 『Goにconst型修飾を期待しなくてよい理由』というセッションでした。

このセッションが印象に残った理由の一つは、const 型修飾に対する分析が非常に明快だったからです。 まずはじめに不変性の説明に必要な概念を導入し、続いてその概念から不変性を分類し、最後に const 型修飾のトレードオフを分析する、という流れが話に説得力を生み、とても惹き込まれるセッションでした。

詳しい内容については スライドを参照いただければと思いますが、この記事では私なりに印象的だった要素をまとめてみようと思います。

3 種類の不変性と限定的な安全性

まず印象的だったのは、不変性には種類があるという点でした。 セッションでは、const型修飾の安全性について語るにあたり、不変性を以下の 3 種類に分類しています。(この分類は、Exploring language support for immutabilityを参考にしたものだそうです)

  • read-only: 読み取り専用
  • ownership: 所有権
  • immutability: 狭義の不変性

このうち、ランタイムを通じて変化しないことが保証されるのは immutability のみであり、const 型修飾は read-only の具体例であるとの説明がありました。 つまり、const 型修飾ではランタイム中に値が変更されるケースがあるため、その不変性から得られる安全性は限定的ということです。 const 型修飾で値が変更される理由の詳解は、スライドに掲載されたコードがわかりやすいです。

int main() {
    int x = 5;
    f(&x, &x);
}

void f(int const * a, int * b) {
    *b = 7;
    assert(*a == 7);
}

このコードでは、変数 a から見ると read-only な不変性を得られてますが、変数 b から見ると可変です。 これは aliasing problem と呼ばれ、ポインタを許す言語で発生するそうです。 また、この限定的な安全性に対して「const なのに可変という状態はデバッグを難解にする可能性がある」という指摘には、個人的に強く納得しました。

const 型修飾によりメンテナンス性が下がる懸念

先述した安全性以外の観点として、メンテナンス性に言及されていたことも印象的でした。

const 型修飾には、const-poisoning という問題があるそうです。 これは、ある const 修飾が他の部分のコードにも const を使うことを強要し、それが連鎖的に広がることでプログラム全体に影響を与える状況を指します。 例えば、引数のバケツリレーに const 修飾子を足して周ることになるかもしれません。

さらにメンテナンス性に関する別の問題として、API 多重度についての指摘もありました。 一般論として、型修飾を増やした際にライブラリの関数は const ありなし両方の型をサポートする必要があるそうです。 このサポートをオーバーロードの機能がない Go で実現しようとすると、似たような関数が重複して生まれてしまい、結果メンテナンス性が下がってしまうとのことでした。 この API 多重度の問題は、実際に strchr という C 言語のライブラリで発生しているそうです。

const 型修飾と Go の設計思想

セッションの結論は、Go に const 型修飾を期待しなくてよい理由は設計思想に反するから、という話で締めくくられました。

Go の設計思想の紹介としては、less is exponentially moreGo's Design Philosophy から次のような抜粋がありました。

ソフトウェアプログラムは、(中略)、プログラミングエラーに優しく、その発生を明確に示し、その影響が予測不可能にならないものでなければならない

問題解決に必要な、強力で理解しやすく使いやすい積み木を提供するだけ

const 型修飾には、部分的な安全性と効率性、型による可読性に寄与するというメリットがある一方で、 限定的な安全性やメンテナンス性が下がるといった点は Go の設計思想に合わないように見え、逆に const 型修飾がないことは Go の設計思想と一貫している、という主張には納得感がありました。

Go には確立された設計思想があるからこそ、こういったトレードオフに直面した際に適切な判断ができるのだろうと感じています。 私はプログラミング言語の開発者ではありませんが、ソフトウェアの開発者として避けられないトレードオフに直面することは多々あります。 二者択一の判断を迫られる場面において、ブレない設計の軸があることの重要性をこのセッションから学ぶことができました。

おわりに

今回 『Goにconst型修飾を期待しなくてよい理由』のセッションについて記事を書かせていただきましたが、他のセッションも Go に対する探究心を感じられる素晴らしい発表ばかりでした。

参加者として非常に楽しく実りある一日となりましたし、ソフトウェアエンジニアとしての活力をいただくことができました。関係者の方々、素敵なイベントをありがとうございました!