Scala – Case Class and Implicit Arguments and Pattern Matching

scala

I tried to combine implicit arguments with case classes, but I got stuck.

case class C(i: Int)(implicit b: Boolean)
val c1 = C(1)(true)
implicit val b = true
val c2 = C(2)
c1 match {
  case C(i)(b) => // doesn´t work
  case C(i,b)  => // doesn´t work
  case C(i)    => // works, but wanted: if (b) i else 0 
}

According to the Scala Language Specification it´s due to the compiler generated extractor object for case classes: My implicit Boolean is not a member of the resulting case class, so it has to be in the second (implicit) argument list (that I can´t find in the companion object´s apply method, unfortunately):

A case class definition of c[tps](ps1 ). . .(psn) with type parameters tps and value
parameters ps implicitly generates an extractor object (§8.1.8) which is defined as
follows:

object c {
  def apply[tps](ps1 ). . .(psn): c[tps] = new c[Ts](xs1 ). . .(xsn)
  def unapply[tps](x: c[tps]) =
    if (x eq null) scala.None
    else scala.Some(x.xs11, . . . , x.xs1k)
}

How can I define a case class with members that are implicitly supplied at creation time?

Best Answer

You can define a case class with implicit arguments, but as you've discovered, they're not available for pattern matching. You could always write your own extractor though:

case class C(i: Int)(implicit val b: Boolean)

// You can't call this C because that seat is taken (can't overload the default unapply)
object C_ { 
  // In order to be able to select `b` here, 
  // it needs to be declared as "implicit *val* b: Boolean"
  def unapply(in: C) = Some((in.i, in.b)) 
}

c1 match {
  case C_(i, b) => ...
}
Related Topic