Lucid Simple

Pattern Matching Helps Reduce Conditional Logic

If you read the post title and thought “no shit, Sherlock”, then you can probably be safe in skipping this week’s post.

If you’d like to hear about another selling point of Elixir that isn’t often mentioned directly, then by all means read on.

This is probably a 2 minute read.

Object Oriented programmers are often preoccupied with avoiding conditional logic.

It is a topic that a lot of smart people have spent a lot of energy on, and the concept even has its own campaign.

Take a look at this example:

function fun(x, y) {
  if (x == 5) {
     if (y == 3) {
       return 7;
     } else {
       return 11;
     }
  } else {
     return y;
  }
}

I don’t think I’m the only one, but when I have to deal with even small amounts of code like this I find that my developer happiness temporarily takes a dive.

But why should it? The little chunk of pseudo code has a lot going for it:

  1. it’s small
  2. it’s only testing with ==
  3. it’s not setting any local variables
  4. it’s not mutating state
  5. it’s only returning integers.

And still, most of the developers I know wouldn’t call this “good” code. To be fair, they probably wouldn’t call it terrible either. But it would be the sort of thing that they would hope to minimize.

And that’s where a lot of brain cycles start to burn up: the conditions themselves are legitimate parts of your domain logic, and they may even be simple when considered one-at-a-time. But when expressed as a whole it somehow transforms itself into an unmaintainable morass.

If you’re clever, then you can mitigate the problem with polymorphism and other OO fare.

But those techniques exact a penalty, too: If you design things correctly, then you’ll pay with indirection. If you design things poorly, then you will still pay with indirection, but you also end up with the wrong abstractions.

As you might have guessed, this is all just a setup to demonstrate how a language with pattern matching (e.g Elixir) handles this problem:

# The "difficult" pseudo code written in Elixir:
def fun(5, 3), do: 7
def fun(5, _), do: 11
def fun(_, y), do: y

The simplicity of this solution makes it the spiritual equivalent of this gif:

Indiana Jones(/assets/jones.gif)

Note how pattern matching allows each condition to live on its own at the top level:

def fun(5, 3), do: 7
def fun(5, _), do: 11
def fun(_, y), do: y

You can parse each case individually without the mental gymnastics needed to keep track of which conditional branch you’re in.

To be clear, this isn’t to say that you should avoid conditionals in Elixir. That would be absurd.

My main point is that the nastiness of nested conditionals often evaporates when using a language that supports pattern matching.

And that using Elixir often feels like bringing a gun to a knife fight.

NOTES

1. Elixir and Erlang aren’t the only languages with pattern matching. If you like Elixir, then you might find OCaml interesting. Others have their own favorites.