I’ve been learning Elixir lately, and so far it’s been fascinating. Elixir is a functional programming language with a very ruby-like syntax. You get immutable state, actor-based concurrency model, and a modern syntax, all running on the Erlang VM. It’s my first foray into functional programming, and I’m enjoying learning the differences between OOP.
This post will get Elixir installed and introduce you to two important parts of Elixir: Immutable Data and Pattern Matching.
Start your dive by installing Elixir. You need at least Erlang R16bB. Don’t worry what that is, just install a precompiled version from here. Next, install Elixir. There are packages here, but you should roll with Elixir from the master branch of the repo for now (Elixir gets a little better every day):
Now you can use interactive mode and start learning:
Press
and then 1
control+c
to get out of that. Interactive mode
keeps a count of the commands you’ve ran in that session (the 1
a
and
1
(1)
). At 1,000 you earn a badge and get a cookie! 11
(2)
Now that you’re up and running, let’s look at some Elixir basics.
Everything in Elixir is immutable. You can’t append to a list; you can only get a new list with those additional items included in it. You cannot increment a value; you can only get a new value returned. Elixir is all about transforming data. Here we think about data and what we’re doing to and with it; we’re not thinking about instances, inheritance, state, or encapsulation.
Let’s look at variable binding, a thing that looks a lot like normal assignment. It’s not. For example:
With assignment (in most OOP languages), the variable
is an object and
references an array of 1
numbers
.1
[1,2,3]
In Elixir, the variable
is now bound to 1
numbers
(which is a List in Elixir, not an array). Outwardly the
same, but a very different thing happened. Binding is more like a
assertion, or a question, “can this statement be made true?”. If you think of
it more as an assertion, then this makes perfect sense:1
[1,2,3]
1
2
3
4
5
6
7
8
# Elixir
iex(2)> a = 1
1
iex(3)> 1 = a
1
iex(4)> 2 = a
** (MatchError) no match of right hand side value: 1
:erl_eval.expr/3
Doing so in Ruby will throw a syntax error. Take note of line 6; this
yields an error because
is bound to 1
a
, and Elixir can’t make 1
1
equal to 1
2
(Elixir will only change the binding of the variable on the
left side). No match for 1
1
could be found, so the assertion fails. Try
thinking “can the left hand side be made to match the
right hand side?”, and then the 1
a
assignment operator becomes a matching
operator.1
=
Immutable data is great because you never have to worry about someone else changing something from under your feet. When you get a block of data, that’s what you get. Not a shared reference to something, you never have to worry about someone else (say another thread of execution) changing that thing you have; they may change something similar, but not your thing. Your thought process and concerns become more local, only worrying about what you’re doing in that particular function with that particular data.
Pattern matching is the process where Elixir binds values to variables,
but not your conventional “assignment”. It’s a fundamental part of
programming here. In the above example with
and 1
a = 1
you saw
the very basics of pattern matching: attempting to make the thing on the left match
the thing on the right.1
1 = a
Some further examples, with lists (not arrays):
1
2
3
4
5
6
7
8
9
10
11
iex(6)> animals = ['dog', 'cat', 'chocobo']
['dog', 'cat', 'chocobo']
iex(7)> [friend, enemy, awesome_bird] = animals
['dog', 'cat', 'chocobo']
iex(8)> friend
'dog'
iex(9)> enemy
'cat'
iex(10)> awesome_bird
'chocobo'
iex(11)>
On line
we make a list of 3 animals, and on line 1
1
we match that
list with a new list, 1
3
. You can then
reference each individually.1
[friend, enemy, awesome_bird]
Look what happens when we try to use the same variable:
1
2
3
iex(11)> [d, c, c] = animals
** (MatchError) no match of right hand side value: ['dog', 'cat', 'chocobo']
:erl_eval.expr/3
In something like Ruby
would simply get assigned (bound) twice
and end up as 1
c
. In Elixir, we’re matching patterns, and the 1
chocobo
variable tries to match both 1
c
and 1
cat
, but can’t. As a
result, the matching fails.1
chocobo
Another example:
1
2
3
4
5
6
iex(1)> [dog, name, dog] = ["Nero", "Adelbert Steiner", "Nero"]
["Nero", "Adelbert Steiner", "Nero"]
iex(2)> dog
"Nero"
iex(3)> name
"Adelbert Steiner"
Here,
matches up with 1
dog
in the first and third position,
allowing 1
Nero
to become whatever it needs to
in order for the match to succeed.1
name
Back to the
example, maybe you’re like me and you don’t actually care about cats. Elixir can
help with a wildcard matcher, the underscore:1
['dog', 'cat', 'chocobo']
1
2
3
4
5
6
7
8
9
iex(12)> [d,_,c] = ['dog', 'cat', 'chocobo']
['dog', 'cat', 'chocobo']
iex(13)> d
'dog'
iex(14)> c
'chocobo'
iex(15)> _
** (ErlangError) erlang error: {:unbound_var, :_}
:erl_eval.exprs/2
On line 7 we get an error when trying to reference
, that’s because
Elixir will match anything there and immediately discard it.1
_
That’s all for now. Go install Elixir if you haven’t already and try out some pattern matching to get a feel for it. Immutable data and pattern matching are important parts of the things I’ll cover in my next Dive Into post covering functions, anonymous functions, and recursive functions.
If you like what you’ve seen, go pick up Programming Elixir from Dave Thomas at The Pragmatic Bookshelf.
no, not really ↩