scalajvmtype-erasureclasstag

Scala: Type annotation of parameter resets ClassTag to Option and spoils type matching


I have a trait with a type parameter. Inside this trait I want to define a method which checks if an object matches the type parameter. So far, this works, as I want it to work:

import scala.reflect.ClassTag
trait MyTrait[A <: AnyVal]{
    def hasType(x: AnyVal)(implicit tag: ClassTag[A]) = x match {
        case _: A => true
        case _    => false
    }
}

object MyObject extends MyTrait[Int]

println(MyObject.hasType(5))   // returns true
println(MyObject.hasType(5.0)) // returns false

The problem occurs when MyTrait-objects are parameters of a class, like here:

class WrappingClass(myObjects: Seq[MyTrait[_]]) {
    def hasType(x: AnyVal) = {
        myObjects.foreach(
            mo => println(mo.hasType(x))
        )
    }
}

object AnotherObject extends MyTrait[Double]
val wrappingObject = new WrappingClass(Seq(MyObject, AnotherObject))
wrappingObject.hasType(5)   // prints only "true"
wrappingObject.hasType(5.0) // prints only "true"

So bassicly the type annotation Seq[MyTrait[_]] of the parameter turns my ClassTag to a general Object and ruins type matching. I really would like to avoid writing the hasType method in each object that inherits from the trait.


Solution

  • You need to use a class with a ClassTag context bound (since those bounds are not utilizable in traits). If you replace MyTrait as:

    abstract class MyTrait[A <: AnyVal: ClassTag] {
        def hasType(x: AnyVal) = x match {
          case _: A => true
          case _ => false
        }
    }
    

    it will works as you expect