Elixir: Data Types, Operators, Pattern Matching and Conditionals

3 minElixir

Elixir is a dynamic, general-purpose, functional programming language. It was created by José Valim, a developer with a background in Ruby, with the specific intent to utilize the scalability and maintainability features of the Erlang platform. Although not the most popular language out there, Elixir is beloved by its users. Companies such as Spotify, Discord, and Heroku have already adopted Elixir for its ease in building distributed, concurrent, and fault-tolerant systems.

Data Types

Like many other languages, Elixir supports basic data types such as integers, floats, strings, and booleans. However, Elixir introduces the atom data type, which is a constant value where the name is its own value.

:hello
:world
:foo
:bar
:ok
:error
elixir

Elixir also has lists, which can hold any data type, and tuples, a collection of data items. There's also the Map data type, a list of key-value pairs, which also exists in other languages.

Operators

Elixir supports boolean operators (&&, ||, !) and comparison operators (===, !== and <) like many other languages. However, it also includes a few more unique ones:

Membership Operator

The in operator checks if an element belongs to a collection. For instance, 1 in [1, 2, 3] or 1 not in [1, 2, 3].

Pin Operator

The pin operator ^ lets you access a variable that already has a value, avoiding rebinding a variable with an existing value. This can be useful when you want to refer to the value prior to the match.

x = 1
x = 2

# 2
elixir
^x = 3 # error

^x = 2 # 2

^x = 1 # error
elixir

Discard Values

Sometimes you may want to discard or ignore values, which can be achieved using the _.

{_, y, _} = {1, 2, 3}
elixir
{_, y, _} = {1, 2}

# error
elixir

Pattern Matching and Conditionals

Pattern matching is a powerful feature in Elixir that allows you to match complex data structures, bind variables to values, and control program flow. Conditionals in Elixir such as if, else, unless, case, cond, and with also play an essential role in controlling program flow.

For instance, consider the following example where we are using pattern matching in an if statement and a case construct.

if, else and unless

color = "blue"
elixir
if color == "blue" do
  "yes"
else
  "no"
end

# "yes"
elixir
if color == "blue", do: "yes", else: "no"

# "yes"
elixir
unless color == "blue" do
  "yes"
end

# nil
elixir

case

This is when we need to match against multiple patterns.

result = {:ok, "success"}

case result do
  {:ok, _result} -> IO.puts "this matches" 
  {:error, _error} -> IO.puts "this won't match"
  _ -> IO.puts "This matches against anything else" 
end
elixir

cond

This is to match against different values.

color = "blue"

cond do
  color == "blue" -> color
  color == "red" -> color 
  color == "green" -> color
  color == "black" -> color
  true -> "the color was #{color}"
end
elixir

with

This is useful when we need more than one match for the code to be executed.

result = {:ok, "something else"}

with {:ok, "result"} <- result do
  result
else {:ok, _result} ->
  "This gets executed" 
end
elixir