0

I would like to pattern-match against a generic parameter. I wrote the following example:

new Cls().processA("")   //prints B: C

sealed trait Tr[A, B <: A, C <: A]{
  def getA(str: String): A

  final def processA(str: String): Unit = getA(str) match {
    case b: B => println(s"B: " + b)
    case c: C => println(s"C: " + c)
  }
}

sealed trait A
final case class B() extends A
final case class C() extends A

final class Cls extends Tr[A, B, C] {
  override def getA(str: String): A = C()
}

I understand that B and C parameters are erasured to their lower bound A. Maybe there is some workaround to pattern-match against type parameters?

St.Antario
  • 26,175
  • 41
  • 130
  • 318

2 Answers2

4

You can use ClassTag so that it will be possible to check this on runtime.

import scala.reflect.ClassTag

sealed abstract class Tr[A, B <: A : ClassTag, C <: A : ClassTag]{
  def getA(str: String): A

  final def processA(str: String): Unit = getA(str) match {
    case b: B => println(s"B: " + b)
    case c: C => println(s"C: " + c)
  }
}

For this to work you need to replace trait with abstract class because traits cannot have type parameters with context bounds.

Łukasz
  • 8,555
  • 2
  • 28
  • 51
2

For this case yes, there is: add import scala.reflect.ClassTag and change the definition of Tr to

sealed abstract class Tr[A, B <: A : ClassTag, C <: A : ClassTag]

Note that this won't affect is/asInstanceOf.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Does it introduce some runtime cost? – St.Antario Sep 24 '18 at 14:37
  • 1
    Yes, but it should be pretty small (of course, saying that isn't a substitute for checking performance in your case). – Alexey Romanov Sep 24 '18 at 14:39
  • Agree. From the quick glance at bytecode generated with `ClassTag`s added it uses `ClassTag:unapply` returning option. So the cost is similar to an `instance of` which is pretty small. – St.Antario Sep 24 '18 at 14:51
  • I have one more clarification. You said that it would not affect `isInstanceOf`, but we can use `implicitly[ClassTag[B]]` to perform the instance checking, can't we? – St.Antario Sep 24 '18 at 14:57
  • Yes, we can. Or matching: `x match { case _: B => true; case _ => false }`. – Alexey Romanov Sep 24 '18 at 15:33