Matching a combination of Case Class and Trait in Scala

870 views
Skip to first unread message

Adam Jorgensen

unread,
Oct 20, 2012, 12:53:22 AM10/20/12
to scala-l...@googlegroups.com
Hi all

So, thanks to http://jcranky.com/2011/12/19/matching-a-combination-of-class-and-trait-in-scala/ I was able to learn the trick of matching a normal class and trait
combination in Scala:

class A
trait B
val c = new A with B
c match {
  case z: A with B => true
  case _ => false
}

This method also works for case classes in the fashion described above:

case class A(i: Int)
trait B
val c = new A(1) with B
c match {
  case z: A with B => true
  case _ => true
}

What I'm wondering through, is if there is a way to properly match the case class instance and it's constructor parameters along with the trait. The following
causes an error about the with statement:

case class A(i: Int)
trait B
val c = new A(1) with B
c match {
  case A(1) with B => true
  case _ =>
}

whereas the following causes a type error because c is an instance of A with B rather than just A.

case class A(i: Int)
trait B
val c = new A(1) with B
c match {
  case A(1) => true
  case _ =>
}

So, is there any way to do this?

Thanks
Adam

Som Snytt

unread,
Oct 20, 2012, 1:44:23 AM10/20/12
to scala-l...@googlegroups.com
On Fri, Oct 19, 2012 at 9:53 PM, Adam Jorgensen <adam.jor...@gmail.com> wrote:

case class A(i: Int)
trait B
val c = new A(1) with B
c match {
  case A(1) with B => true
  case _ =>
}


So, is there any way to do this?


scala> trait Foo
defined trait Foo

scala> case class Fooz(s: String)
defined class Fooz

scala> class Foob extends Fooz("goo") with Foo
defined class Foob

scala> val a = Fooz("foo")
a: Fooz = Fooz(foo)

scala> val b = new Foob
b: Foob = Fooz(goo)

scala> def f(x: Fooz) = x match {
     | case Fooz(y) if x.isInstanceOf[Foo] => s"Foob $y"
     | case Fooz(y) => s"Only Fooz $y"
     | }
f: (x: Fooz)String

scala> f(a)
res0: String = Only Fooz foo

scala> f(b)
res1: String = Foob goo

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Foob extends Fooz("goo") with Foo
object Foob {
def unapply(x: Fooz) = x match {
case _: Foo => Some(x)
case _ => None
}}

// Exiting paste mode, now interpreting.

defined class Foob
defined module Foob

scala> def f(x: Fooz) = x match {
     | case Foob(y) => s"Foob $y"
     | case Fooz(y) => s"Only Fooz $y"
     | }
f: (x: Fooz)String


Adam Jorgensen

unread,
Oct 20, 2012, 6:40:04 AM10/20/12
to scala-l...@googlegroups.com
Thanks!

Michael Cotterell

unread,
Oct 20, 2012, 2:16:18 PM10/20/12
to scala-l...@googlegroups.com
This looks like it might be good for our lecture too.
--
Sincerely,
Michael E. Cotterell

Ph.D. Student in Computer Science, University of Georgia
Graduate RA & TA, University of Georgia
mepcot...@gmail.com
mep...@uga.edu
m...@cs.uga.edu
http://michaelcotterell.com/
Ontology Basic Concepts.pdf

Jon-Anders Teigen

unread,
Oct 26, 2012, 5:11:10 AM10/26/12
to scala-l...@googlegroups.com
// the extractor of enlightenment
object & {
  def unapply[A](a:A) = Some(a -> a)
}

case class A(i: Int)
trait B

val c = new A(1) with B

// to allow the case class extractor we ascribe 'A with B' to 'A'
// the '&' extractor allows us to match the same thing twice, 
// where we use a typed pattern on the right to ensure its a 'B'
(c:A) match {
  case A(1) & (_:B) => true
}

// this opens up even more possibilities.
// if we want to match both using 'A' as a case class, and regain the full typeinformation 'A with B', we can simply
// use the 'A with B' as a typed pattern (like the original example) on the right hand side and bind it to the variable 'x' which will 
// have the desired type 'A with B' as we can see from the return type.
val y:A with B = (c:A) match {
  case A(1) & (x:(A with B)) => x
}

/j

Reuben Doetsch

unread,
Oct 27, 2012, 7:26:25 PM10/27/12
to scala-l...@googlegroups.com
+1

杨博

unread,
Dec 7, 2012, 10:58:20 AM12/7/12
to scala-l...@googlegroups.com
I used to believe that all case class would better to be final. I still remenber the compiler error when I create a class that extends another case class.

在 2012年10月20日星期六UTC+8下午12时54分07秒,Adam Jorgensen写道:

Atry

unread,
Dec 7, 2012, 11:26:00 AM12/7/12
to scala-l...@googlegroups.com
BTW: Have you tried this:

case class YourCaseClass(parameter: Int)
trait Trait
val any: Any = new YourCaseClass(123) with Trait
any match {
  case caseClassWithTrait @ YourCaseClass(parameter) if caseClassWithTrait.isInstanceOf[Trait] =>
}

2012/12/7 杨博 <pop....@gmail.com>
Reply all
Reply to author
Forward
0 new messages