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!")
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
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")
defmodule Playground do
#Normal Function
def area(a, b) do
a * b
end
end
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
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
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)
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
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"}
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:
- Check if the data type matches the expected data type
- Check if the data structure matches the expected data structure
- 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)