Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Case Class and Implicit Arguments and Pattern Matching

Tags:

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?

like image 771
Peter Schmitz Avatar asked Mar 15 '11 17:03

Peter Schmitz


People also ask

Which method of case class allows using objects in pattern matching?

Case classes are Scala's way to allow pattern matching on objects without requiring a large amount of boilerplate. In the common case, all you need to do is add a single case keyword to each class that you want to be pattern matchable.

What is case class and pattern matching Scala?

Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.

How does Scala pattern matching work?

Pattern matching is a way of checking the given sequence of tokens for the presence of the specific pattern. It is the most widely used feature in Scala. It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C.

What is case class in Scala with example?

Scala case classes are just regular classes which are immutable by default and decomposable through pattern matching. It uses equal method to compare instance structurally. It does not use new keyword to instantiate object. All the parameters listed in the case class are public and immutable by default.


2 Answers

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) => ...
}
like image 131
Alex Cruise Avatar answered Feb 08 '23 04:02

Alex Cruise


Alex's answer is clever, however I don't really like the _ in the object name, I find the syntax a little strange and remembering the underscore makes pattern matching more difficult to use. (Of course this is all subjective so your feelings may vary).

My first approach to dealing with this were to move the implicit parameters to the apply method in the companion object.

case class A(i: Int, b: Boolean)

object Foo {
  def apply(i: Int)(implicit b: Boolean): Foo = apply(a, b)
}

But this results in

Error:(21, 14) double definition: 
method apply:(i: Int, b: Boolean)com.workday.cloud.master.package.A and 
method apply:(i: Int)(implicit b: Boolean)com.workday.cloud.master.package.A at line 24 
have same type after erasure: (i: Int, b: Boolean)com.workday.cloud.master.package.A   
  case class A(i: Int, b: Boolean)
             ^

We can fix this by adding an extra unused implicit parameter.

object A {
  def apply(i: Int)(implicit b: Boolean, unused: DummyImplicit): A = apply(i, b)
}

Which approach you choose is up to you, I find this approach enables my client code to look more natural.

like image 32
iain Avatar answered Feb 08 '23 02:02

iain