ネタが尽きたわけではないが、Manifest絡みで嫌な現象に遭遇したのでメモと回避方法(現在はManifest
型をつかうべきではないがそれはおいておく)。
まず、問題として、次のようなコードを書くと実行時例外(unknown error
)が発生する(Scala 2.10.4)。
trait M[T] {
implicit val m: Manifest[T]
}
case class Point(x: Int, y: Int)
object Main extends M[Point] {
implicit val m: Manifest[Point] = manifest[Point]
def main(args: Array[String]) {
json4sObj.extract[Point]
}
}
このようになる原因は、traitでの初期化でmanifest
メソッドを呼び出すとnull
が返ってくることにあるようだ(manifest
メソッドはscalacで特別な扱いを受けていることに関連していると思われる)。それならと、manifest
呼び出しのタイミングを遅らせるように
trait M[T] {
implicit def m: Manifest[T]
}
case class Point(x: Int, y: Int)
object Main extends M[Point] {
implicit def m: Manifest[Point] = manifest[Point]
def main(args: Array[String]) {
json4sObj.extract[Point]
}
}
としてみると、今度は
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
at Main$.m(M.scala:8)
というStackOverflowErrorが発生する。これの回避策だが、
implicit def m
の部分を
implicit def m()
に書き換えればOK。つまり、最終的なコードは以下のようになる。
trait M[T] {
implicit def m(): Manifest[T]
}
case class Point(x: Int, y: Int)
object Main extends M[Point] {
implicit def m(): Manifest[Point] = manifest[Point]
def main(args: Array[String]) {
json4sObj.extract[Point]
}
}
これでうまく行く理由、というより、一つ前のコードがうまく行かなかった理由が釈然としないのだが…(コンパイラが暗黙に想定しているimplicitなManifest[T]
を上書きしてしまったせいではないかと推測している)