I had heard about Pattern Matching before and was totally clueless about it. But when I started learning Elixir it soon struck me: the equal sign works differently.

Usually, in programming the equal sign performs an assignment.

So if you have a expression like:

foo = 7

Would usually mean you’re evaluating the expression on the right, and are storing the result in the variable on the left.

foo = ["b", "a", "r"]

Here for instance, most languages will consider this list on the right an entity ["b","a","r"] and will store this entity (or reference to it) in the variable on the left - foo.

Sounds reasonable right ?

This is not how it works in Elixir.

The Equal Sign In Elixir

In Elixir (and in Erlang) the equal sign performs a pattern matching operation.

What is pattern matching ?

It is just as the name implies.
Elixir will try to make the expressions on both sides be equal.

In different words: it will make whatever it can so that things on the left can equal the things on the right.

This is not limited to 1 variable.

In the above case it would still work mostly as you imagine, with a slightly different naming, it is called variable binding.

In the first example Elixir would bind the variable foo to 7.

foo = 7

In the second example, foo would bind to the list ["b", "a", "r"]

foo = ["b", "a", "r"]

However, this would also work:

[foo, bar, ho] = ["b", "a", "r"]

Yes.
foo binds to "b", bar binds to "a" and ho binds to "r".

Awesome, isn’t it ?

Similarly:

["b", bar, ho] = ["b", "a", "r"]

Left Wing matching

Elixir will only bind variables on the left side though.

So for instace, if you do this in sequence:

foo = 7

foo = ["b", "a", "r"]

This will work fine.

However, this will not:

foo = 7

["b", "a", "r"] = foo

Since now foo is 7 and it is on the right, Elixir will not bind it to something else.

And what happens when the match fails ?

In the above case, the match will fail. Because as mentioned, Elixir cannot bind the values on the left to foo.
In this case, a Match Error will be raised.

** (MatchError) no match of right hand side value: 7

This means Elixir was unable to match what you told it to.
Bad, bad match!

More examples

Another thing you can do is match when the data structure carrying different data types.
For example:

[a, b] = ["foo", 42]

As you can imagine, a bind to "foo" and b to 42.

You can even match a list within a list.

[a, b, c] = ["foo", 42, ["hello","little", "alchemist"]]

And besides a and b continuing as before, now c will bind to ["hello","little", "alchemist"].
And you can even go one step futher and do:

[a, b, [c, d, e]] = ["foo", 42, ["hello","little", "alchemist"]]

And now c,d and e will bind to "hello", "little" and "alchemist" respectively.

Maps

One very common thing to do in Elixir is pattern match Maps, which is super powerful.

This is how you define a map in Elixir:

%{"key" => "foo"}

Coming from java this was a weird syntax, so take your time to process it if you’ve never seen it before.
It’s simple, it means the string "key" is a key in your map, and retrieving it will get you the value "foo".

Now, back to the pattern matching, you can obviously bind this to a variable:

my_map = %{"key" => "foo"}

And also, as mentioned, retrieve the value "foo" into a variable similarly:

my_value = my_map["key"]

foo

But here it comes:

%{"key" => my_value} = %{"key" => "foo"}

Here the map on the left has to equal the map on the right.
For this to happen, my_value needs to equal "foo", and that’s precisely what happens.

For pattern matching to work on maps, the keys need to match - which is happening here.
So Elixir binds the value on the left, to the value on the right.

And you can even do this storing the map on a variable:

my_map = %{"key" => "foo"}
%{"key" => my_value} = my_map

Here, my_value will still bind to "foo".
Elixir try to make the maps on both side match. So as long as the keys match, it will bind the value on the left (my_value), to the value on the right "foo".

In other words, it has the same effect as doing this:

my_value = my_map["key"]

As long as the key of the map match, you can use variables as you please - just keep in mind that again, only the left side will be able to bind variables.

The Pin Operator ^

Say you want to match the value stored within your variable.
When you would like to put the variable on the left, but you don’t want Elixir to bind it to something else.

In this case you can use the pin operator: ^. Then, you can match using value stored within the variable, not as a normal variable.

foo = 3
[^foo, bar] = [3, "awesome"]

Let’s understand what this means.
This will match when foo is already equal to 3. It will not match when foo it is not 3, and it will not bind foo to 3.

This, for instance, will raise an Error:

foo = 3
[^foo, bar] = [5, "not good"]

** (MatchError) no match of right hand side value: [5, “not good”]


Cool. Now process all of this and take a moment, because we have one last trick. And it’s tricky.

Pattern Matching a Map on function argument

This is my favourite.

You have a function, and you receive a map as an argument. And you need the value that comes from the key "foo".

my_map = %{"foo" => "bar"}
my_function(my_map)

Let’s say you want to define this my_function. You want that to print the value stored on the key "foo" from the argument map.
How to achieve this ?

You can do this like so:

def my_function(%{"foo" => my_variable}) do
  IO.puts my_variable
end

Now if we go ahead and pass in a map to your function, it’s gonna retrieve the right value:

my_map = %{"foo" => "bar"}
my_function(my_map)

“bar”

Boom! Headshot!


That’s it for today! A very interesting topic and I will surely further expand on another post in the future.

Hope you enjoyed it, Don’t forget to like the post and share with your friends - It’s only fair to share!

And until next time, Take care and happy brewing!