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 を行っていたのでした。残念。
まあ動作が違ったら違ったでこんな基本的な構文の結果が違ってもいいのかという突っ込みになっただろうけど。
コメント 0