I have a case class like the following:
// parent class
sealed abstract class Exp()
// the case classes I want to match have compatible constructors
case class A (a : Exp, b : Exp) extends Exp
case class B (a : Exp, b : Exp) extends Exp
case class C (a : Exp, b : Exp) extends Exp
// there are other case classes extending Exp that have incompatible constructor, e.g.
// case class D (a : Exp) extends Exp
// case class E () extends Exp
// I don't want to match them
I want to match:
var n : Exp = ...
n match {
...
case e @ A (a, b) =>
foo(e, a)
foo(e, b)
case e @ B (a, b) =>
foo(e, a)
foo(e, b)
case e @ C (a, b) =>
foo(e, a)
foo(e, b)
...
}
def foo(e : Exp, abc : Exp) { ... }
is there a way to merge that three cases into a single case (without adding an intermediate parent class to A,B,C)? I can't change the definition of A, B, C, or Exp. Some sort of:
var n : Exp = ...
n match {
...
case e @ (A | B | C) (a, b) => // invalid syntax
foo(e, a)
foo(e, b)
...
}
which obviously does not work, and neither do:
var n : Exp = ...
n match {
...
case e @ (A (a, b) | B (a, b) | C (a, b)) => // type error
foo(e, a)
foo(e, b)
...
}
Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the switch statement in Java and it can likewise be used in place of a series of if/else statements.
Gettings Our Ducks in a Row Fortunately, Scala allows us to write idiomatic code to achieve the same results as duck typing. As we see in the example above, we can declare a structural type at most places where a type constraint is expected: type alias, method's parameter types, or a lower type bound.
It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C. Here, “match” keyword is used instead of switch statement. “match” is always defined in Scala's root class to make its availability to the all objects. This can contain a sequence of alternatives.
The name comes from the phrase, “If it walks like a duck and it quacks like a duck, then it must be a duck.” Duck typing is related to dynamic typing, where the type of the class of an object is going to be less important than the methods that it defines.
While the following "solution" is really just a different way of writing what you already have, it might help if you need to use the same match
in more than one place and want to avoid code duplication.
The following custom unapply:
object ExpABC {
def unapply(e:Exp):Option[(Int, Int)] = e match {
case A(a, b) => Some(a, b)
case B(a, b) => Some(a, b)
case C(a, b) => Some(a, b)
case _ => None
}
}
allows you to write
n match {
case e @ ExpABC(a, b) =>
println(e)
println(a)
println(b)
}
This way you don't need to modify the original classes at all. I'm not aware of a better way to do this that doesn't involve modifying the A/B/C classes, but I'm eager to learn @ Stackoverflow ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With