Reputation: 309
Look at this code.
trait SomeMix {
}
trait Processor[T] {
def processMix(t: T with SomeMix) = {
println("processing T with Mix")
}
def processAsUsual(t:T)= {
println("processing T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix) // <---- error here
case _ => processAsUsual(t)
}
}
}
Stupid Scala compiler shows error here:
Error:(22, 39) type mismatch; found : mix.type (with underlying type SomeMix) required: T with SomeMix case mix: SomeMix => processMix(mix)
It does not understand that expression I matching to SomeMix is already of type T. Ok lets help him. Changed code:
def process(t:T) = {
t match {
case mix: T with SomeMix => processMix(mix) // <---- warning here
case _ => processAsUsual(t)
}
}
Now it agrees that all is correct but show warning:
Warning:(22, 17) abstract type pattern T is unchecked since it is eliminated by erasure case mix: T with SomeMix => processMix(mix)
Is any good way to avoid both error and warning here?
Upvotes: 1
Views: 300
Reputation: 51703
You can do this at compile time like @ppressives proposed. If you really want to do this at runtime you should find a way to keep types there after compile time. In Scala standard way to do this is TypeTags.
Try
import reflect.runtime.universe.{TypeTag, typeOf}
def typ[A: TypeTag](a: A) = typeOf[A]
def process(t: T)(implicit ev: TypeTag[T with SomeMix], ev1: TypeTag[T]) = {
t match {
case mix if typ(t) <:< typeOf[T with SomeMix] => processMix(mix.asInstanceOf[T with SomeMix])
case _ => processAsUsual(t)
}
}
val p = new Processor[Int] {}
p.process(10) //processing T
val p1 = new Processor[Int with SomeMix] {}
val ten = 10.asInstanceOf[Int with SomeMix]
p1.process(ten) //processing T with Mix
Check
Pattern match of scala list with generics
Pattern matching on generic type in Scala
Upvotes: 1
Reputation: 170899
Since, as you mention, it's definitely an instance of T
, you can just suppress the unchecked warning:
case mix: (T @unchecked) with SomeMix
Note that it's still unchecked and at runtime only tests that the matchee is an instance of SomeMix
; if you change to e.g.
def process(t: Any) = ...
you'll get bad results.
Upvotes: 1
Reputation: 51
Scala compiler is not stupid. You can't check t is instance of T with SomeMix
because of type erasure. Instead of dynamic type dispatching try to use typeclasses with static dispatching.
For example
trait SomeMix {
def someMethod: String = "test2"
}
class SomeType
def process[T](t: T)(implicit P: Process[T]): Unit = P.process(t)
trait Process[T] {
def process(t: T): Unit
}
implicit val processString: Process[SomeType] = s =>
println(s"processing $s as usual")
implicit val processStringWithSomeMix: Process[SomeType with SomeMix] = s =>
println(s"processing $s with mix ${s.someMethod}")
process(new SomeType)
process(new SomeType with SomeMix)
Upvotes: 2
Reputation: 2582
Like this?
trait SomeMix {
}
trait Processor[T] {
def processMix(t: SomeMix) = {
println("processing SomeMix")
}
def processAsUsual(t:T)= {
println("processing T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix)
case _ => processAsUsual(t)
}
}
}
Upvotes: 1