DEV Community

Cover image for Elixir - A brief introduction to the language behind WhatsApp, Nubank, Brex, and so many others!
Lucas Matheus
Lucas Matheus

Posted on

Elixir - A brief introduction to the language behind WhatsApp, Nubank, Brex, and so many others!

Author's Note: "Hi everyone, the goal of this article, as the title suggests, is not to present all aspects of the functional programming paradigm, but rather to demonstrate the usefulness of the Elixir language and its differentiating factor compared to other programming languages. I came into contact with this language in the Distributed Systems course and, initially, it didn't make much sense to me that the professor would address this language. However, I later understood its importance for systems that can be easily scalable and resilient, with critical services."

Introduction

Elixir is a functional programming language. With functional languages ​​like Elixir, we can make better use of our multi-core CPUs and write shorter, more explicit code. To better understand functional programming, I must first introduce the following fundamental principles: immutability, functions, and declarative code.

In functional programming, all values ​​created in the program are immutable. By default, each function has a stable value, meaning that locking mechanisms are not necessary. This simplifies parallel work. Immutability is appearing more in conventional programming languages. These languages ​​typically provide the immutable mechanism, providing an alternative immutable data type or a method to make a value immutable.

The Elixir syntax shares many similarities with Ruby syntax and is widely used to build fault-tolerant, scalable, and maintainable applications. The language provides scalability, concurrency, fault tolerance, and low latency.

The language also has a solid set of web development tools, such as:

Mix: Mix is ​​a build tool that allows you to create projects, run tests, manage tasks, and much more.

IEx: IEx, Elixir's interactive shell, offers many features such as auto-completion, debugging, code reloading, and more.

Phoenix: Phoenix is ​​known for being one of the best web frameworks. It is based on the MVC architecture, just like Ruby on Rails.

Importance of Elixir

Elixir is fundamental if you want to build a system that can operate in a distributed manner. Furthermore, it's a great choice for developing microservices. Facebook Messenger was initially built using Elixir's Erlang base. However, it was rewritten in another language years later. Even so, WhatsApp still has parts developed with Erlang and Elixir.

Nubank acquired a company called "Plataformatec," where one of the founders is the creator of the Elixir language. The functional paradigm also helps in Nubank's internationalization process. "Since it's an immutable paradigm, we don't need to change everything from scratch," says Bruno, the tech manager at Nubank. "The logic of a country's financial system may be different from another's, but we can use the same foundation for everyone."

Brex, a banking payments technology company founded by two Brazilians, adopted Elixir as a way to create consistent systems for payment operations. In an article written by one of the founders, he pointed out the following: "After using Elixir for 18 months, we have a strong understanding of how the platform behaves in the real world. One observation is that, despite Elixir being a relatively niche language, new hires who have never had contact with Elixir before are productive within three weeks. There is a reasonable amount of books and documentation available on the language that accelerates the learning process."

A brief introduction

Primitive Types

Strings

Elixir uses the UTF-8 standard for string encoding. Strings are the same in any other language. In the example below we have the output of a string in the terminal.

IO.puts("Hello, World!")
Enter fullscreen mode Exit fullscreen mode

Atoms

Atoms are constants whose value is their own name. In other languages, such as Ruby, for example, atoms are called symbols. elixir

iex> :cat
:cat
iex> :dog
:dog
iex> :fish
:fish
Enter fullscreen mode Exit fullscreen mode

Booleans Booleans are values ​​that can be true or false.

true

true==false

Keyword List When we have a list of tuples and the first item in the tuple has an atom, we call this structure a Keyword List. Below is an example of a Keyword List.

list = [{:c, 1}, {:d, 2}]
[c: 1, d: 2]
iex> list == [c: 1, d: 2]
true

Modules and Functions

In elixir, functions are grouped into modules. In the example below, we see function calls and a function. Simple:

String.length("elixir")
Enter fullscreen mode Exit fullscreen mode
defmodule Playground do

#Normal Function
def area(a, b) do
a * b
end
end
Enter fullscreen mode Exit fullscreen mode

It's important to note that in elixir there is no return keyword; therefore, the return is based on the output of the last line. Below is an example of a function without arguments:


# Function with no arguments

def run do
area(10,20)

end
Enter fullscreen mode Exit fullscreen mode

When you have a single-line return, you can do it like this:


# Clean Way to do one-line function

def area_of_circle(x, y) do: x * y
end
Enter fullscreen mode Exit fullscreen mode

Anonymous Functions

As the name indicates, an anonymous function has no name. As we saw in the Enum lesson, they are frequently passed to Other functions. To define an anonymous function in Elixir, we need the keywords fn and end. Within these, we can define any number of parameters and bodies separated by ->.

# Anon Function
s = fn x -> x * x end

s.(2)

# Output: 4

sum = fn (a, b) -> a + b end
sum.(2, 3)

Enter fullscreen mode Exit fullscreen mode

Pattern Matching

Pattern matching is a way to associate an expression in Elixir. Pattern matching cannot be limited to association with variables; we can perform this with functions.

{name, age} = {"John", 25}
name #Output: "John"
age #Output: 25
Enter fullscreen mode Exit fullscreen mode

The underscore operator (_) allows you to avoid direct associations with values, which is very useful when you want to use constants. The underscore operator is also called an anonymous variable.

{_, x} = {11, "Hello"}
Enter fullscreen mode Exit fullscreen mode

The usefulness of pattern matching with functions in Elixir allows you to create multiple clauses for the function. Elixir uses pattern matching to check all possible match options and identify the first set of associated parameters to execute its respective body.

``elixir
handle_result = fn
{:ok, result} -> IO.puts "Handling result..."
{:ok, _} -> IO.puts "This would be never run as previous will be matched beforehand."
{:error} -> IO.puts "An error has occurred!"

end
`

In this code, we associate an anonymous function with a variable that can return three different types of results depending on the tuple input. Below is another example of pattern matching applied in a named function:

`elixir
defmodule Geometry do
def area({:rectangle, a, b}) do
a * b
end

def area({:square, a}) do
a * a
end

def area(:circle, r) do
r * r * 3.14159
end

def area(unknown) do
{:error},{:unknown_shape, unknown}

end

`

Give yourself a variable/value, you might want to:

  1. Check if the data type matches the expected data type
  2. Check if the data structure matches the expected data structure
  3. Assign the corresponding part of the data to a variable

Examples:

Check if the data are maps

elixir
%{} = params

We can, for example, perform three checks: Check if the data is a map, has the key "email", and the value "email" corresponds to a given input.

elixir
%{"email" => "zoo@example.com"} = params

Variable assignment. In this case, it will check if the key "email" exists in the tuple; if it does, the value of the key "email" will be assigned to the variable my_email.

%{"email" => my_email} = params

We can do the same with anonymous variables.

elixir
%{"email" => _} = params

struct type check
elixir
%User{} = params

Check if the data are tuples and have a specific value

`elixir
{:ok, data} = result

you use this most of the time

`

Named Functions

We can define functions with names to refer to them in the future; these named functions are defined with the def keyword inside a module. We will learn more about Modules in the next lessons; for now, we will focus only on named functions. Below is an example of a named function that returns the size of a list:

elixir
defmodule Length do
def of([]), do: 0
def of([_ | tail]), do: 1 + of(tail)
end

References

https://news.ycombinator.com/item?id=21111662
https://medium.com/brexeng/why-brex-chose-elixir-fe1a4f313195
https://elixir-lang.org/docs.html
https://github.com/samsepiol1/study_elixir

Correction

Apparently, Brex decided to change its codebase from Elixir to Kotlin, although it still acknowledges that Elixir was of great importance in the initial stages: https://medium.com/brexeng/building-backend-services-with-kotlin-7c8410795e4b

Top comments (0)