Using generic case classes in Scala

Alexey Alexandrov picture Alexey Alexandrov · Sep 17, 2013 · Viewed 15.2k times · Source

I wonder whether using generics for Scala case classes can save some boilerplate code.

Let's save I have the following class hieararchy to emulate a "variant" type that boxes a set of types and allows unboxing them using pattern matching:

sealed abstract class Box;

case class DoubleBox(v: Double) extends Box;
case class StringBox(v: String) extends Box;
case class BooleanBox(v: Boolean) extends Box;

def typeName(b: Box) = b match {
  case DoubleBox(v) => "Double"
  case StringBox(v) => "String"
  case BooleanBox(v) => "Boolean"
  case _ => "Unknown"
}

There may be places in the code where it would be more convenient to deal with the leaf case classes if they were generics. Something like:

sealed abstract class Box;

case class TypedBox[T](v: T) extends Box;

def typeName2(b: Box) = b match {
  case TypedBox[Double](v) => "Double"
  case TypedBox[String](v) => "String"
  case TypedBox[Boolean](v) => "Boolean"
  case _ => "Unknown"
}

But this doesn't compile. As far as I understand this syntax is not really recognized as valid Scala syntax.

Is it possible to make what I want working or it's a bad idea and I just don't get something?

EDIT: Vinicius answered my question, but looking at the answer I have another question. Is it possible to hint the compiler somehow that only certain list of types can be used to parameters TypedBox? I want that to make sure the compiler can still do exhaustiveness check of TypedBox usage/matching.

Answer

Vinicius Miana picture Vinicius Miana · Sep 17, 2013

Try

sealed abstract class Box;

case class TypedBox[T](v: T) extends Box;

def typeName2(b: Box) = b match {
  case TypedBox(v: Double) => "Double"
  case TypedBox(v: String) => "String"
  case TypedBox(v: Boolean) => "Boolean"
  case _ => "Unknown"
}