FGJを読む(2)
2016-10-25
Techということで3章から読んでいきます。URL等は第一回を参照してください。
3. FEATHERWEIGHT GJ
FGJのサンプルプログラムがあります。コメントを足しつつ転記します。
// 2つのオブジェクトの組
class Pair<X extends Object, Y extends Object> extends Object {
X fst; // フィールド定義
Y snd;
// コンストラクタ
Pair(X fst, Y snd) { super(); this.fst = fst; this.snd = snd }
// インスタンスメソッドsetfst
// 引数を第一要素とする新しいペアを返す
<Z extends Object> Pair<Z, Y> setfst(Z newfst) {
return new Pair<Z, Y>(newfst, this.snd);
}
}
// クラスAとBがあるとします
class A extends Object{ A() { super(); }}
class B extends Object{ B() { super(); }}
// メイン部分 (FJではメインプログラムをソースコード末尾に書きます)
new Pair<A, B>(new A(), new B()).setfst<B>(new B());
言語仕様の簡略化のためクラス定義時のextendsが省略できない、とかはFJと同じです。型パラメータ定義時のextends Objectも省略できないのでちょっとうるさい感じになっていますが、それはおいといて、「クラスもメソッドも型パラメータを持てる」ということの例のようです。クラスPairはXとYが型パラメータ、メソッドsetfstはZが型パラメータです。
それぞれの型パラメータは上界(bound)を持ちます。extends Objectというのが上界の指定ですね。
クラスAとBは型パラメータを持ちませんが、これらは0個の型パラメータを持つと考えることができます(あえて書くならA<>
, B<>
)。
GJとの違い
上のメインではsetfstメソッドを呼ぶときに型パラメータ<B>
を明示しています。
new Pair<A, B>(new A(), new B()).setfst<B>(new B());
が、FeatherweightじゃないほうのGJではこの<B>
は省略できます。自動で推論されるということですね。省略できるというか、必ず省略しなければならない(上のように書くことはできない)ので、FGJはFJの厳密なサブセットにはなっていません。型パラメータの推論は重要だけど、この論文ではGJのそれ以外の側面に注力したとのことです。
型パラメータの上界について
型変数の上界についていくつかのことが書かれています。
- 上界は型変数であってはいけない (
<X extends Y>
みたいのはだめ、ということかな) - が、型変数を含む型式ならOK (
<X extends Array<Y>>
とかですかね) - 再帰的な定義も許される
<X extends Array<X>>
はOK
- 相互再帰も許される
<X extends Array<Y>, Y extends Array<X>>
はOK
いやあ、こんな変なケースのことは全然考えてなかったですね…。これらのケースの具体例がGJの論文にあるそうですが、それはまた次回。