Considering the following code:
object DelayedClassTagInference {
trait SS {
type TT <: Any
implicit val ctg: ClassTag[TT] = implicitly[ClassTag[TT]]
val fakeCtg: ClassTag[None.type] = implicitly[ClassTag[None.type]]
}
class Sub1 extends SS {
override final type TT = Int
}
class Sub2 extends SS {
override final type TT = Double
}
class Sub3 extends SS {
override final type TT = String
}
}
class DelayedClassTagInference extends FunSpec {
import DelayedClassTagInference._
it("") {
val sub1 = new Sub1()
println(sub1.fakeCtg)
println(sub1.ctg)
}
}
When Sub1 & Sub2 are initialised, type TT is already determined, so ClassTag[Int] and ClassTag[Double] can be easily inferred by using type class rules.
Unfortunately, when I run the above code. I got the following result:
scala.None$
null
So the value of ctg is null, besides from triggering an NullPointerException, this also doesn't make sense. Is it a scala bag that should be fixed later?
Remove modifier
implicitforval ctgand you'll see that your code doesn't compile. You shouldn't define implicitClassTag/TypeTag/WeakTypeTagmanually, they should be generated by compiler automatically when type is known.Actually when you call
implicitly[ClassTag[TT]]the implicitval ctg: ClassTag[TT]you're defining right now is used, that's why it'snullat runtime.Implicits are resolved at compile time and, when you call
sub1.ctg, resolving which.ctgis called happens at runtime (that's how subtyping polymorphism works). At compile time it's not known yet that it'sSub1#ctg.Replace
with
and you'll have
Intat runtime instead ofnull.