SSブログ

Scala の Variance の話の続き [Scala]

Scala 2.6.0 で新規追加された existential type と Scala の既存機能の variance annotation の関係について調べたり考えたりしていた。既存の variance annotation のこともよくわかっていなかったなあ。

前回 [1] 書いたように covariant な型に対して出来る操作は基本 get のみである。逆に言うとパラメタ化された型が immutable であれば covariant な型付けは安全だし失うものは何もない。そこで Scala では従来から型パラメタに + を付けることによってコンパイラに covariant なサブタイピングを指示出来る。これを以下のような関数的なリスト構造で確認してみる。まずは + なしから。

scala> abstract class MyList[T]
defined class MyList

scala> case class MyNil[T] extends MyList[T]
defined class MyNil

scala> case class MyCons[T](head: T, tail: MyList[T]) extends MyList[T]
defined class MyCons

scala> val ints = MyCons(123, MyNil[Int])
ints: MyCons[Int] = MyCons(123,MyNil())

scala> val vals: MyCons[AnyVal] = ints
<console>:7: error: type mismatch;
 found   : MyCons[Int]
 required: MyCons[AnyVal]
val vals: MyCons[AnyVal] = ints
                           ^

Scala はデフォルトでは invariant なサブタイピングであるため上記はコンパイルエラーとなる。これを以下のようにするとコンパイルを通る。

scala> abstract class MyList[+T]
defined class MyList

scala> case class MyNil[+T] extends MyList[T]
defined class MyNil

scala> case class MyCons[+T](head: T, tail: MyList[T]) extends MyList[T]
defined class MyCons

scala> val ints = MyCons(123, MyNil[Int])
ints: MyCons[Int] = MyCons(123,MyNil())

scala> val vals: MyCons[AnyVal] = ints
vals: MyCons[AnyVal] = MyCons(123,MyNil())

うっかり前者のように + なしでクラスを定義してしまっていても Scala 2.6.0 からは以下のように救済(?)できる。

scala> val vals: MyCons[T] forSome { type T <: AnyVal } = ints
vals: MyCons[T] forSome { type T <: AnyVal } = MyCons(123,MyNil())

ここで疑問。「『 + 付き』で MyCons を定義していた場合の MyCons[AnyVal] 」と、「『 + 無し』で MyCons を定義していた場合の MyCons[T] forSome { type T <: AnyVal } 」は、型名は違うけど同じ型だと考えてよいのだろうか? 何か違いが出る状況はあるのか? それからひょっとして existential type のみをサポートしていれば従来からの variance annotation は不要になるとも言えるのだろうか? こうした微妙な点がまだよくわからない。

[1] http://blog.so-net.ne.jp/rainyday/2007-07-29


nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。