TL;DR
- Go のジェネリクスは、当初の Contracts 案を撤回し、既存の interface で型制約を表す形になった。
- その設計の基礎が Featherweight Go で、ジェネリックなコードの変換を定式化している。
内容
Contracts の撤回
Go のジェネリクスには、もともと Contracts という概念を導入する予定だった。しかし、新しい概念が増えることや、型の振る舞いを定義できる interface がすでにあることから、撤回された。
Featherweight Go
Featherweight Go は、Go のジェネリクスの設計思想を表し、ジェネリックなコードをどう変換するかを定式化したものである。Featherweight Java に強く影響を受けており、Featherweight Java の FJ と FGJ に対応して、FG と FGG というモデルがある。
設計の要件は、使いやすく理解しやすいこと、ランタイムコストが低いこと、可能な限り保守的な拡張であることの 3 つである。方針として、構造的部分型とジェネリクスを組み合わせ、追加の言語機能なしに型制約を導入し、モノモーフィゼーションに基づいてコンパイルする。
FG は Go をチューリング完全な関数型の言語としてモデル化したもので、ジェネリクスを含まない。FGG は FG を拡張し、構造体、メソッド、インタフェースが型パラメータを持てるようにしたものである。型パラメータの制約には interface を使う。
コンパイル戦略
コンパイル戦略は Featherweight Java とは異なる。FJ と FGJ はコンパイル時に型情報を消すイレイジャを使い、FG と FGG は型ごとに専用のコードを生成するモノモーフィゼーションを使う。
コンパイル時には、ダミーメソッドが生成される。使われていないメソッドを省くと空のインタフェースが生成され、すべての型がそれを満たしてしまうので、型安全性が崩れる。
Expression Problem
FGG では Expression Problem(式問題)を共変レシーバで解決する。ただし、リリースされた Go のジェネリクスは不変(invariant)な設計を採用しており、共変レシーバは入っていない。
キーワード
- Go
- ジェネリクス
- Featherweight Go
- Featherweight Java
- モノモーフィゼーション
- チューリング完全
- Expression Problem