Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala duck typing pattern matching

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)
    ...
}
like image 796
Lie Ryan Avatar asked Oct 03 '12 16:10

Lie Ryan


People also ask

How does Scala pattern matching work?

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.

Does Scala have duck typing?

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.

What does match mean in Scala?

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.

Why is it called duck typing?

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.


1 Answers

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 ;)

like image 67
fresskoma Avatar answered Oct 05 '22 22:10

fresskoma