Pattern matching around type erasure

You may have encountered this warning: "scala non-variable type argument in type pattern is unchecked since it is eliminated by erasure". If you google for it, you quickly find several decent Stack Overflow and forum replies that will suggest you to structure your code differently or use Type Manifests. They may even mention that there is an option to write custom extractor, but most of the time without transparent code sample. I decided to write this post to give such an easy-to-grasp code snippet.

Let's prepare the scene. Assume we have some generic class, which actual instance type will be erased.

class Container[T](data: T) {
  def get = data
}
// Let's simulate type erasure, otherwise Scala compiler will
// figure out the type. It is really that smart :)
def stored: Container[_] = new Container("hello")

Next, our straightforward pattern match may work in some cases, but will generate a warning and will not be able to distinguish for the type of the generic:

stored match {
  case c: Container[String] => println(c.get)
  // The second condition will never be executed
  case c: Container[Int] => println("Int " + c.get)
}

But it is very easy to create an extractor object:

object Container {
  def unapply[T](x: Container[T]) = Some(x.get)
}

Now you can use it hassle-free:

stored match {
  case Container(data: String) => println(data)
  case Container(data: Int) => println("Int " + data)
}

But what if you want to match on a type of generic, but still have the entire container object, not its content? That is simple as well:

stored match {
  // "x" will be the entire container
  case x @ Container(_: String) => println(x)
  case x @ Container(_: Int) => println("Int " + x)
}

This functionality is well documented and is safe to be used.

Posted On

Category:

Tags: / /