my code is as below.
case class C[T]() {
val pf:PartialFunction[Any,Any] = {
case i:T => i
}
}
println(C[Int]().pf.isDefinedAt(-1.0))
this prints true
. Why this happens?
my code is as below.
case class C[T]() {
val pf:PartialFunction[Any,Any] = {
case i:T => i
}
}
println(C[Int]().pf.isDefinedAt(-1.0))
this prints true
. Why this happens?
Due to type erasure your code is basically equal to:
case class C[T]() {
val pf:PartialFunction[Any,Any] = {
case i:Any => i // this matches everything
}
}
you can use TypeTag
s to fix it:
import scala.reflect.runtime.universe._
case class C[T: TypeTag]() {
def pf[U: TypeTag]: PartialFunction[U, Any] = {
case i if typeOf[U] <:< typeOf[T] => i
}
}
in use:
@ C[Int]().pf.isDefinedAt("")
res41: Boolean = false
@ C[Int]().pf.isDefinedAt(34)
res42: Boolean = true
these are virtually equal to
@ C[Int]().pf[String].isDefinedAt("")
res41: Boolean = false
@ C[Int]().pf[Int].isDefinedAt(34)
res42: Boolean = true
where the type U
is inferred - it has a limitation that it can only be as precise as compiler's knowledge about the type when TypeTag
is required.
You can also try to use ClassTag[T]
to use runtime reflection... but it would fail for primitives
case class C[T]()(implicit classTag: scala.reflect.ClassTag[T]) {
def pf[U: TypeTag]: PartialFunction[U, Any] = {
case i if classTag.runtimeClass.isInstance(i) => i
}
}
which results in
@ C[Int]().pf.isDefinedAt(34)
res2: Boolean = false
@ C[Int]().pf.isDefinedAt("")
res3: Boolean = false
Thing is classTag
would resolve to Scala's int
while runtime would show java.lang.Int
:
@ case class C[T]()(implicit classTag: scala.reflect.ClassTag[T]) {
def pf: PartialFunction[Any, Any] = {
case i => println(s"T = ${classTag.runtimeClass.getName}, here: ${i.getClass.getName}")
}
}
defined class C
@ C[Int]().pf.isDefinedAt(34)
res7: Boolean = true
@ C[Int]().pf(34)
T = int, here: java.lang.Integer
res8: Any = ()
In general there is no perfect solution here, you can read more about similar questions here and here.