Scala Goodies: Pattern matching with typed lists or Working around Scala's type erasure

Last updated:
Scala Goodies: Pattern matching with typed lists or Working around Scala's type erasure
Source

If you ever try to perform pattern matching on a Generic type (for example, List[Int]), you'll find out that you can't. Not in Scala anyway:

// lets define a list of Ints
val list1:List[Int] = List(1,2,3,4,5,6)

// and then try to pattern match on it
list match {
  case l:List[String] =>  "it's a list of strings"
  case l:List[Int] =>  "it's a list of ints"
}

This will return "it's a list of strings" even though our input is a list of Ints.

This is because of something called type erasure.

Due to the way Java code is compiled and run, generic types aren't available at runtime.

Once your Java code is compiled, the Java Runtime does not know it was ever a generic type. So in order to support seamless interoperability with Java, Scala needs to play by the same rules, and this is why you have Type erasure in Scala.

There are a few ways to work around that, it seems (though none are particularly elegant). A simple search on google will show you many results. If you only need to pattern match on Lists that only contain a single type, the following technique may be of use to you.

This particular workaround only works with Lists of a single type

Quick solution using reflection

Must add scala-reflect to dependencies, e.g.: libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.12.8"

import scala.reflect.runtime.universe._

def processList[T: TypeTag](list: List[T]) = {
    typeOf[T] match {
      case t if t =:= typeOf[String] => "it's a list of strings"
      case t if t =:= typeOf[Int]    => "it's a list of ints"
    }
}

val ints: List[Int] = List(1, 2, 3, 4, 5)
val strings: List[String] = List("foo", "bar", "baz")

println(processList(ints))
// prints "it's a list of ints"

Dialogue & Discussion