SSブログ

MSIL 版 Scala のジェネリクス [Scala]

Java Generics の Reification の章を読み始めている。型の情報がランタイムまで完全に残っている場合それは reifiable な型という風に呼ばれるが、Java では昔からの配列は reifiable だけど generics はそうではなくて例えば List<Integer> は List にされてしまって(これを erasure と呼ぶ)、型パラメタの情報は実行時には利用できない。これはキャストを行ったり実行時にオブジェクトの型についての問い合わせをする場合に意識しなければならない。Java はこのような方針を採用することによってクライアントはレガシーなままライブラリをジェネリックにアップグレードしても相互運用可能であるというような高い後方互換性を実現している。

さて Scala は JVM バイトコードにコンパイルされる都合上、 Java と同様にジェネリクスを erasure によって実現している。そして以下のような case 文では実行時にオブジェクトが何の型であるかという情報を利用する必要があるから上述の問題が表れる。

case class Container[T](v: T)

object TryMe {
  def f(x: Any) = x match {
    case a: Container[Double] => "double"
    case a: Container[Int] => "int"
    case _ => "other"
  }
  def main(args: Array[String]) = {
    Console.println(f(Container(1.23)))
    Console.println(f(Container(1)))
  }
}
PS D:\scala> scalac TryMe.scala
warning: there were unchecked warnings; re-run with -unchecked for details
one warning found
PS D:\scala> scalac -unchecked TryMe.scala
TryMe.scala:5: warning: non variable type-argument Double in type pattern is unchecked since it is eliminated by erasure

    case a: Container[Double] => "double"
            ^
TryMe.scala:6: warning: non variable type-argument Int in type pattern is unchecked since it is eliminated by erasure
    case a: Container[Int] => "int"
            ^
two warnings found
PS D:\scala> scala TryMe
double
double

しかし Java Generics の本によると C# のジェネリクスというのは Java とは違った方針に基づいていて、generic な型も reifiable である、つまり実行時にも型パラメタも含めた型情報が利用できるらしいのだ。

じゃあ Scala の .NET 版はひょっとして?と思うのが当然なので scala-msil を nightly build からとってきて(これのステータスってどういう扱いなんだろうか)実際に試してみた。

PS D:\scala> scalac-net -unchecked TryMe.scala
TryMe.scala:5: warning: non variable type-argument Double in type pattern is unchecked since it is eliminated by erasure

    case a: Container[Double] => "double"
            ^
TryMe.scala:6: warning: non variable type-argument Int in type pattern is unchecked since it is eliminated by erasure
    case a: Container[Int] => "int"
            ^
two warnings found
PS D:\scala> ilasm TryMe.msil > $null
PS D:\scala> ./TryMe.exe
double
double

結果は同じで、Scala は .NET 版でも Java と同じように erasure を行っていたのでした。残念。
まあ動作が違ったら違ったでこんな基本的な構文の結果が違ってもいいのかという突っ込みになっただろうけど。


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

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

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