Elixir: An introduction (Part One)

Nicola Luongo
5 min readDec 24, 2020

Trying different programming languages is a great way to have your assumptions challenged and push your mind to expand. In this article, we will go over Elixir’s history, its programming paradigm, what it asks us to do and what we get in return.

Origin

Elixir is a fairly new language, especially when compared to Java and Python, two languages that had been around for decades. While its first appearance was in 2011, it’s now standing on solid ground and it’s an increasingly important asset to any business implementing embedded systems or real-time communications systems. Companies that hoped on the Elixir train early, such as Heroku and Discord, are now reaping the benefits.

Even though Elixir is a new language, its core and foundation is not. Elixir is compiled into the BEAM, Erlang’s original virtual machine. Erlang is a language that was specifically built for distributed computing before the 90s. It has been battle tested for decades in the telecommunications industry. It could be argued that Elixir took upon Erlang’s mantle and made distributed computing more accessible to everyone.

Elixir can invoke any Erlang code and leverage thousands of libraries that were written before Elixir was born (Erlang came about in 1986). So, there’s a great chance that somebody wrote a library in Erlang that could be used in Elixir by invoking it directly from Erlang or by writing a thin wrapper around it.

A lot of the credit (if not all) goes to Jose Valim, Elixir’s mastermind who envisioned a language that was not only easy on the eyes, but also a highly concurrent — a language that is able to spawn thousands, if not millions, of processes with a small memory footprint. He succeeded in creating a language that developers love because of its maintainability, simplicity to write and its incredible performance in distributed environments.

As of now, the Elixir team has just released version 1.11 and they do not show signs of slowing down. The language has a very strong presence in web development under the Phoenix framework. Besides, Elixir is actively gaining terrain in the field of embedded applications with the framework Nerves.

Elixir’s entry price

In the majority of universities around the world, the imperative paradigm reigns supreme, meaning that we tell the computer exactly what to do to execute a computation or obtain a result. For example, add the value from register zero to the one in register two and place the result in register three. This reads exactly like an order.

Elixir forces us to break away from this paradigm and instead immerse ourselves into functional programming. In other words, we will have to model our computations in terms of functions — and nothing but functions. The upside is that (almost) all of them will be side-effect free leading to deterministic and predictable programs. We are only asked to make sure that the functions in our program return something.

Functional programming

Almost everything in Elixir is a function (broadly speaking), including the equivalent of the conspicuous if statement from other languages.

a = if x > 3, do: 2, else: 3

This expression will result in a being assigned either 2 or 3 depending on the value of x . You can think of this as passing a boolean expression to the if function.

An extra commitment from our part, will be ensuring that every function returns something, which is a necessary condition for a function to be a function. The program will not compile if said condition is not satisfied.

Here follow some simple functions to illustrate the point:

def sum(x,y), do: x + ydef constant_two, do: 2def long_fn(a, b) do
# a long computation ...
:ok
end

The first function models arithmetic addition: it returns the sum of the two numbers given to it. The second function always returns the number 2 . The third function always returns the atom :ok , which could be abused as a procedure and then use the :ok atom to assert some sort of result. The point being: functions must always return something.

Pattern matching

Another enemy to wrestle with early on, will be pattern matching. You will have to train yourself to interpret the = sign a different way — a rather ample way. Pattern matching makes programs more assertive and less verbose.

Let’s define a map (the rough equivalent of an object in JS) and try to pattern match against its structure. In other words, we will do both variable declaration and assignment in one go.

map = %{a: 3, b: "foo"}
# Now let's pull the values of the a and b keys from the map
%{a: a, b: b} = map
# Now a holds the value of 3 and b the value of "foo"
a
# 3
b
# "foo"

As long as the left side matches the structure of the right side, we can match and store values inside variables. This is similar to the destructuring capabilities present in modern JavaScript.

Elixir’s freebies

Elixir comes with immutability built-in, and it ought to be respected at all times. Immutability does not mean that we are restricted only to a few variables (or values) in our program. In fact, new values can be obtained by creating new copies from older data (unneeded data will be ultimately garbage collected). As memory is very cheap in the present, this is very a small price to pay for the benefits of parallel computation and a more deterministic runtime.

a = 2
# a holds the value of 2
a = 3
# a holds the value of 3 - from this point on this is a new copy of the variable and we can use it to create even more values as we see fit

This rather trivial example hides one of Elixir’s guarantees: Multiple processes can grab a value from memory at any given time with no risk of the value being mutated. That location in memory is reserved to that particular variable holding that value; it cannot be overwritten unless that memory is freed, meaning that value is no longer needed and thus safe to discard. This is a necessary condition for fearless concurrency and parallel computations.

Elixir’s runtime is fairly performant if we consider a single threaded (or a single process context). However, from a broader point of view, it has the ability to run the same program multiple times and on multiple cores with no risk of data corruption and no performance penalty.

This cannot be said about C, or C++, two languages that are faster but that come with a high risk of crashing simply from overwriting a piece of memory that has not been freed. In fact, fearless concurrency in the C family of languages is very, very hard to get right, if not impossible. Even a simple multi-threaded program is at risk of being bug-laden.

Elixir’s greatest merit lies upon solving this problem elegantly and abstracting it away from the developer. In other words, Elixir offers developers primitives that make distributed computing at scale a real possibility, from programs that are easier to read, write and maintain. The language not only protects developers from some common programming errors, but also makes developers more productive as some family of bugs will not be able to crop up inside the system.

Get Started

Go onto Elixir’s site to learn more about it.

Try elixir’s online REPL

To be continued…

We will take an even closer look at the language in the upcoming chapters.

--

--

Nicola Luongo

Passionate about making programming accessible, productive and fun