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)な設計を採用しており、共変レシーバは入っていない。

キーワード

関連