Elixir: from 0 to spawn() in 30 minutes

Introduction

A bunch of tutorials already exist online. But while me and @tjsousa were making the slides for the Lisbon Elixir Meetup, I thought that it’d be great to have something like that prior to reading the “Programming Elixir” book.

So, here it goes, a little summing up and refactor of the code presented on those slides, an intro to Elixir! Take into account that you should revisit each of this topics as there is a lot more to talk about than on this short intro.

I really recommend you to go typing along each part of this tutorial and run and mess with the stuff I present you here.

Installing Elixir

You can either go native, and install Elixir directly on your machine or you can use Docker.

Follow this link for going native.

If you rather go and use Docker, use this repository (yeah, I know, it’s mine, shameless self promotion. But I try hard to always keep it up to date).

IEx

Elixir’s very own REPL which also allows to run the REPL with your project code loaded into it.

Mix

The Jack of all trades. Create projects, run test, execute commands. The bundler of Elixir, with a twist, you can extend it.

Hex

Package manager (abstracted into mix)

Ex_doc

HTML documentation generator.


Alright, let’s get to code! Start your iex and your clock :D


Pattern matching

Let’s talk about pattern matching. Pattern matching is a away to associate and filter variables on runtime.

iex> {a, b} = {1, “2”}  
{1, “2”}
iex> a  
1  
iex> b  
“2”

Here we associate a to 1 and b to “2”. Sweet!
Pattern matching can also be applied on functions. Think “method overloading on steroids”:

iex>  
defmodule ZeroToSpawn do  
  def foo({var1, var2, “bar”}) do
    var1
  end
  def foo({_, var2, “baz”}) do
    var2
  end
end  
{:module, ZeroToSpawn,…>>, …
iex> ZeroToSpawn.foo {1,2,”bar”}  
1  
iex> ZeroToSpawn.foo {1,2,”baz”}  
2  

So here we define that the function foo has a different behaviour when it receives different tuples. This is awesome for code flow and error handling for example.

You might’ve also noticed the defmodule. This is the way to organize your functions into different Modules.

We also saw our first function definition. Let me show you a bit more on that next.

Function definition

Besides defining a function inside a module, you can also define anonymous functions:

iex> fn(x) -> x + 1 end  
#Function<… in :erl_eval.expr/5>
iex>  fn(x) -> x + 1 end.(1)  
2  

This function simply adds 1 to x. In order to invoke anonymous functions, you have to use the syntax .(arguments).

But you can also have this function defined in much less chars via the compressed form. The following function does exactly the same as the previous:

iex> &(&1+1)  
#Function<… in :erl_eval.expr/5>
iex> (&(&1+1)).(1)  
2  

Or if you’d like to name the anonymous function:

iex> add_1 = &(&1+1)  
#Function<… in :erl_eval.expr/5>
iex> add_1.(1)  
2  

Lists

Lists in Elixir are represented through []. Here are some examples:

iex> [1,2,3,4]  
[1, 2, 3, 4]
iex> [“a”,2,”c”,4]  
[“a”, 2, “c”, 4]
iex> [%{a: 1},%{b: 2}]  
[%{a: 1}, %{b: 2}]

List transformations and operations are a big part of Elixir. The Enum module offers many useful operations off the batch. IMO this is one of those implementations that every programming language should have when it launches.

As you might’ve guessed, Enum functions can be applied to Lists. This happens because List implements the Enumerable type.

Besides all the Enum functions, Elixir has an awesome syntax through pattern matching to work with lists:

iex> [head | tail] = [1,2,3,4,5]  
[1, 2, 3, 4, 5]
iex> head  
1  
iex> tail  
[2, 3, 4, 5]

This kind of operation can be really useful on this kind of operations:

iex>  
defmodule ZeroToSpawn do  
 def max([x]), do: x
 def max([ head | tail ]), do: Kernel.max(head, max(tail))
end  
iex> ZeroToSpawn.max([1,2,3,4,9,5,6])  
9  

Pipe |> Operator

This is one of the coolest things in Elixir.

Imagine you have these three functions:

iex>  
defmodule ZeroToSpawn do  
 def x(val) do val-2 end
 def y(val) do val*2 end
 def z(val) do val-1 end
end  

If you wish to apply to function x the result of invoking y with the value 2, you’d have to:

iex> ZeroToSpawn.x(ZeroToSpawn.y(2))  
2  

This is a bit awkward to read. You have to go to the end of the line to understand that the function that is actually first executed is Test.y and only then is it’s value used on Test.x.

Elixir has an elegant form of solving this issue through the pipe operator |>. The pipe operator takes the result of a function and feeds it into the next function as the first argument. So on this example it’d be as simple as:

iex> 2 |> ZeroToSpawn.y |> ZeroToSpawn.x  
2  

Pretty much more readable huh? You can keep chaining these calls too
:

iex> 2 |> ZeroToSpawn.y |> ZeroToSpawn.x |> ZeroToSpawn.z  
1  

Sweet!

Recursion

In the previous lists example we took advantage of the recursion call on the max function through pattern matching. We cannot speak about recursion without giving the mother of all recursion examples, Fibonacci algorithm in Elixir:

iex>  
defmodule ZeroToSpawn do  
 def fib(0) do 0 end
 def fib(1) do 1 end
 def fib(n) do fib(n-1) + fib(n-2) end
end  
iex> ZeroToSpawn.fib(10)  
55  

Note: Jędrzej noticed that this is not a Tail Call Optimized Fibonacci algorithm. Not using Tail Call Optimization can bite your ankles really hard when your stack starts getting deep. Curious? Read more about it here. And here’s a TCO’d version for the Fibonacci algorithm.

Alright, now that we’re through with this, let’s get into the best part of Elixir :D

Processes

Erlang VM offers the ability to spawn processes. These processes are not the Operative System processes, they’re known as green threads and are completely managed by the Erlang VM. This means they are very lightweight, with a very small footprint, which allows you to use and abuse them. Another cool factor is that they’re totally isolated between themselves. Add this to imutable data structures and you’ve just swiped out of the way a crap-load of concurrency issues.

Spawning a process is really simple:

iex> spawn fn -> IO.puts “hi” end  
hi  
#PID<0.154.0>

The code for IO.puts was executed in an isolated process. As for the #PID<0.154.0> part, this represents the Process Identifier for the spawned process. Through this PID you can send messages to the target process, which brings us the the concurrency model adopted by Erlang VM.

In Erlang VM an Actor Concurrency Model scheme was adopted. Each process has a mailbox where it receives messages. These messages are pattern matched in order to be processed.

Let’s see how we can do this (self refers to the current running process):

iex> send self(), {:message, “hi there”}  
{:message, “hi there”}
iex> receive do  
   {:message, content} -> IO.puts “Message received: #{content}”
 end
Message received: hi there  
:ok

Notice we send the message before instructing the process to receive it. This happens because receive will actively wait for a message and only loop out after receiving it.

Since this is a bit cumbersome, let’s make a nicer example. We’ll define a module to handle the message receiving and spawn it:

iex>  
defmodule ZeroToSpawn do  
  def greet do
    receive do
      {:message, content} -> IO.puts “Message received: #{content}”
      {:message} -> IO.puts “Message received with no content”
      _ -> IO.puts “Unknown command received, ignoring :D”
    end
    greet
  end
end  
iex> pid = spawn &ZeroToSpawn.greet/0  
#PID<0.84.0>
iex> send pid, {:message, “hi there!”}  
Message received: hi there!  
{:message, “hi there!”}
iex> send pid, {:message}  
Message received with no content  
{:message}
iex> send pid, {:bar}  
Unknown command received, ignoring :D  
{:bar}

Notice we referenced ZeroToSpawn.greet via &ZeroToSpawn.greet/0, which basically means “the function (&) in the ZeroToSpawn module, named greet, which has 0 arguments as input (/0).

What's next?

So now you’ve got a pretty good introduction to Elixir. There are some topics I exposed here that definitely need more depth. I advise you to now go along and follow the official getting started guide. You’ll go into awesome topics like String manipulation, Maps, Dicts, Structs or Comprehensions.

If you’re into web apps development, take a look at the great Phoenix Framework - it’s a Rails’ish type of framework made in Elixir.

Also take a look to the next great thing that is at your disposal: OTP and some cool abstractions of processes. Through OTP - which is also provided by the gurus who made Erlang - you can guarantee resilience and availability for your applications in Elixir.

Thanks for reading!

I’ll be posting some more Elixir stuff in the time to come! If you have any kudos, flames, suggestions or any kind of feedback please feel free to drop a comment or ping me.