コントラクトはインタフェースのシンタックスシュガーになるのか #golang

December 25, 2019

本稿はGo5 Advent Calendar 2019の25日目の記事です。 本稿で扱っている内容は今後変更される可能性があり、必ずしもGoのバージョンアップで取り込まれるというようなものではありません。

GopherCon 2019のIan Lance Taylor氏のGenerics in Goというセッションとその後公開されたDesign Docではコントラクトという機能が紹介/定義されています。

Design Docに登場したコントラクトは以下のように、型パラメタへの制約定義したものです。

contract C(P1, P2) {
	P1 m1(x P1)
	P2 m2(x P1) P2
	P2 int, float64
}

// コントラクトCを用いて関数fの型パラメタに制約をかけている
func f(type P1, P2 C) (x P1, y P2) P2 {
	// (略)
}

コントラクトCは型P1と型P2対して以下のような制約を加えています。

  • P1はメソッドm1(x P1)を持つ
  • P2はメソッドm2(x P1) P2を持つ
  • P2int型またはfloat64型のいずれか

GopherCon 2019の時のDesign Docではこのようにインタフェースとは別にコントラクトという機能が増えるという記述がされていました。

そして、Design Docと同時に公開されたコントラクトを含むコードをパースして試すためのCL187317も公開されました。この変更はコンパイラの修正では無い上に本体にマージされることはありません。コンパイラに手を加える前に、とりあえず先にgoパッケージに手を入れて抽象構文木を取得できるようにして試すためのものです。

しかし、2019年12月16日(JST)でCL187317に大きな変更が加わりました。その変更では、上記で書いたコントラクトは下記のようなインタフェースで書くことができるとされています。

type I1(type P1) interface {
	m1(x P1)
}

type I2(type P1, P2) interface {
	m2(x P1) P2
	type int, float64
}

func f(type P1 I1(P1), P2 I2(P1, P2)) (x P1, y P2) P2 {
	// (略)
}

Go1.13時点のインタフェースでは、type int, float64のような記述はできません。 おそらくこの記述はI2インタフェースを実装するには、int型またはfloat64型を基底型として取るような型である必要があるという意味であると考えられます。 また、関数fのように関数の型パラメタにインタフェースを指定することに型に制約を加えることができるようになっています。

このようにコントラクトは拡張されたインタフェースのシンタックスシュガーになる可能性があります。 CL187317にも書いてあるように埋め込みなど、まだまだ、考慮不足の点があるので今後の議論を見守っていきたいです。