Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested vs flattened pattern match in Scala

Let's say that I have n values in Scala named v1, v2, ..., vi, ..., vn of types Tij that are not necessarily different types for different i. I want to pattern match against the n values using a custom logic.

One way to do it is to nest all possibilities in case I need to be exhaustive (which for the sake of this example I need to be, otherwise I could use placeholder mag_c) and I can't merge branches (which for the sake of this example I can't as every custom logic is unique):

v1 match {
  case x1: T11 => v2 match {
    case x2: T21 => v3 match {
      ...
        case xn_1: Tn_11 => vn match {
          case xn: Tn1 => // Custom logic 1.
          case xn: Tn2 => // Custom logic 2.
          ...
          case xn: Tnk => // I am already laughing, but I have to write it down: 
                          // Custom logic k.
        }
        ...     
      ...
    }
    case x2: T22 => v3 match {
      // I guess you get the point. 
    }
    ...
  case x1: T12 => v2 match {
    // And so on until exhaustion in every meaning of the word.
  }
  ... // These three dots are needed here. Now I feel whole.      
}

The other option is to flatten the whole darn thing out:

(v1, v2, ..., vn) match {
    case (x1: T11, x2: T21, ... xn: Tn1) => // Custom logic 1.
    case (x1: T11, x2: T21, ... xn: Tn2) => // Custom logic 1.
    ...
    case (x1: T11, x2: T21, ... xn: Tnk) => // Custom logic k (with a hearthy chuckle).
    ... // Three dots saving my soul and my finger joints.
}

While the nested version avoids duplicate typing, it can lead to hard-to-read code due to indentation overflow when n is high (and we are not).

On the other hand, the flattened version contains a lot of duplicate code, but is easier to interpret.

Also, the nested version seems to be more performant as the checking of xi happens maximum once per type Tij (but perhaps I should not care about such things as the JVM could just optimize it all away, and I don't want to be all evil).

Which one is idiomatic Scala code and is therefore recommended? Is there a performance difference between the two versions?

like image 970
bugfoot Avatar asked Jan 22 '19 09:01

bugfoot


People also ask

Does Scala have pattern matching?

Notes. 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.

Is pattern matching faster than if else?

It turned out that pattern matching in their example was significantly faster than if-else tests. Even though the code doesn't utilize any special pattern match cases that would not be possible with if-else tests, it just compares integers.

What is case class and pattern matching in Scala?

It is defined in Scala's root class Any and therefore is available for all objects. The match method takes a number of cases as an argument. Each alternative takes a pattern and one or more expressions that will be performed if the pattern matches. A symbol => is used to separate the pattern from the expressions.


1 Answers

You should pick the option that most closely expresses the meaning of your code and not worry about performance. If the performance of this match is critical to your code then you have bigger problems with your design. (It is also not clear that one performs better than the other, so choosing based on assumed performance would be unwise).

If every case leads to an independent piece of code, then having a flat match is the most direct expression of the logic. Adding spurious nesting is just going to confuse things.

If there is some common code between two or more case expressions then they can be grouped into nested match statements so that the common code is not duplicated. This may also apply if there is some logical commonality between multiple cases that you want to expresses in the code.

Also note that you can chain partial functions using orElse which allows you to split one big match into separate functions with meaningful names, while avoiding nested match statements.

like image 170
Tim Avatar answered Nov 05 '22 05:11

Tim