Reputation: 3180
Why the isInstanceOf[T]
method is not working as intended?
In the following, I have defined a hello
class and companion object. In the hello object, I test this.isInstanceOf[T]
in the line of codes " hel.typetest[Int]
", how come this is true
when the type T
is Int
?
object hello {
def main(args: Array[String]): Unit = {
Console.println("main")
val hel = new hello
hel.typetest[Int]
}
}
class hello {
def typetest[T: ClassTag]: Unit = {
Console.println(this.isInstanceOf[T])
Console.println(this.getClass)
}
}
Output:
main
true
class hello
Upvotes: 3
Views: 938
Reputation: 989
After searching lots of posts and fighting the type erasure warning, I came across this stack overflow answer Implicit ClassTag in pattern matching
Based on that post, I created the following implicit type matcher to check if an object is or is not an instance of the generic type T. Hope this helps someone.
import scala.reflect.ClassTag
object ObjectExtensions {
implicit class IsType(obj: Object) {
def isType[T](implicit tag: ClassTag[T]): Boolean = obj match {
case tag(_: T) => true
case _ => false
}
}
}
** edited: After more investigation, instead of using isInstanceOf[T] you need to use classTag[T].runtimeClass.isInstance(objectToCheck) as noted by Alexey Romanov's answer.
import scala.reflect.ClassTag
object ObjectExtensions {
implicit class IsType(obj: Object) {
def isType[T : ClassTag](): Boolean = {
classTag[T].runtimeClass.isInstance(obj)
}
}
}
Upvotes: 0
Reputation: 170735
Because of type erasure (together with boxing). T
erases to Object
, so this.isInstanceOf[T]
becomes this.isInstanceOf[Object]
in bytecode which is always true.
As it happens, ClassTag
is intended to avoid this, but you need to actually use it instead of calling isInstanceOf
:
def typetest[T](implicit tag: ClassTag[T]): Unit = {
Console.println(tag.runtimeClass.isInstance(this))
}
There's also special-case support for pattern-matching against T
when a ClassTag
is present:
def typetest[T: ClassTag]: Unit = {
Console.println(this match {
case _: T => true
case _ => false
})
}
There were proposals to make is
/asInstanceOf[T]
work correctly when a ClassTag
is present too, but there are assumptions built into the compiler which prevent this and would be too hard to change (if I remember the reason correctly).
Upvotes: 8