Elixir Data Types (Part 2)
May 23rd, 2021
In this post, we will look at Elixir data types: integer, float, booleans, string, lists, maps, tuples... I will try to make this article concise as possible.
Getting Started
This post expects that you fiddle with the language by writing code to try out any of the given examples. Typing out these examples yourself helps improve memory muscles. So you are expected to have Elixir installed on your machine and you can run the interactive shell.
Visit the installation page once you are done run elixir --version
to make sure that your installation matches the below requirements:
- Elixir 1.5.0 onwards
- Erlang/OTP 19 onwards
Interactive Shell
When the installation is completed, you will have 3 binaries added to your PATH
: iex
, elixir
, and elixirc
. You should start the interactive shell by running iex
(iex.bat
on Windows Command Prompt or PowerShell) to startup Elixir in interactive mode. We can type an expression and get a result in this shell.
Let's warm-up by running the below expression:
Erlang/OTP 23.0 [64-bit] [smp:2:2] [...]
Interactive Elixir (1.11.4) - press Ctrl+C to exit
iex(2)> "hello" <> " world"
"hello world"
Now we can push forward because we've been able to ascertain that Elixir is installed and we can access the interactive shell.
Numbers
Elixir sees the integer
and float
as two distinct types even though they fall under the Number
category.
iex> 1 # integer
iex> 0x1F # integer
iex> 1.0 # float
Open up the iex
if you haven't, and let's see the possible arithmetic operations we can perform using numbers — you can perform more complex operations than the examples show.
iex> 1 + 1
2
iex> 20 - 5
15
iex> 8 / 4
2.0
iex> 7 * 7
49
iex> 0b1010 # binary
10
iex> 0o777 # octal
511
iex> 0x1F # hexadecimal
31
As seen in the example above you will notice that the expression 8 / 4
returns 2.0
which is a float value. This is expected in Elixir because the /
operator always returns a float even the numbers used are integers like we have above. So if you to perform some integer operations without losing to the float
you should invoke the div
and rem
functions for division and remainder of division respectively — I know we've not talked about functions yet but be rest assured we will.
iex> div(8, 4)
2
iex> rem(9, 2)
1
Floats require a dot followed by a digit, and you can also use e to denote scientific notations.
iex> 1.0
1.0
iex> round(3.9) # the round function rounds up to nearest integer
4
iex> trunc(2.56) # the trun function gets the integer part of a float
2
iex> 1.0e-10
1.0e-10
Booleans
Elixir supports true
and false
as boolean values, this means that you can't use any other datatype to depict a boolean value.
iex> true
true
iex> false
false
iex> is_boolean(true)
true
iex> is_boolean(0)
false
Note that Elixir provides a bunch of predicate functions to use to check for a value type: is_boolean
, is_number
, is_integer
, is_float
...
Atoms
An atom is a constant whose value is its name. Some other languages call these symbols. - Elixir Docs
iex> :ok
:ok
iex> :error
:error
iex> :sent
:sent
One thing to keep at the back of your mind is that Atoms are mostly used to depict the state of an operation so don't be surprised when you see it thrown around in an Elixir project 😄
NOTE: The booleans are also atoms, you can confirm this by running the predicate function is_atom(true)
or is_atom(false)
.
Strings
A string is a sequence of characters delimited by double quotes and they are encoded in UTF-8 and interpolation of variables is allowed in a string.
iex> "Welcome to Elixir"
"Welcome to Elixir"
iex> name = "Reader"
iex> "I look forward to you loving Elixir, #{name}."
"I look forward to you loving Elixir, Reader"
iex> "hellõ wørld"
"hellõ wørld"
And you can test if a value is a string using is_binary
predicate function while using String.length
and byte_size
to get the length of a string and the number of bytes in a string.
iex> is_binary(true)
false
iex> is_binary("am I a string?")
true
iex> String.length("beginner")
8
iex> byte_size("Elixir")
6
Lists
As the name implies, Lists are used to hold a collection of items, any data type. The square brackets [
and ]
are used to denote a list.
iex> list = [1, 2, 3, "elixir", true]
[1, 2, 3, "elixir", true]
iex> length(list)
5
And note that a List in Elixir is a linked list unlike other programming languages
iex> list = ["Charles", "Turing", "José"]
["Charles", "Turing", "José"]
iex> hd(list)
"Charles"
iex> tl(list)
["Turing", "José"]
You should the hd
and tl
to grab the head and tail of a list respectively. And there is the ++
and --
operator to append and subtract from a list. See the example below:
iex> [1, 2, 3, 4] ++ [5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
iex> [1, 2, 3, 4] -- [3, 2]
[1, 4]
Maps
Map is basically a key-value store. It's created using the %{}
:
iex> lang = %{name: "Elixir", paradigm: "Functional", creator: "José Valim"}
%{name: "Elixir", paradigm: "Functional", creator: "José Valim"}
iex> lang[:name]
"Elixir"
iex> lang[:paradigm]
"Functional"
iex> lang.creator
"José Valim"
Below are characteristics of a map:
- The map allows any value as its keys meaning that you can have a string, atom, number...
- The keys are not ordered
Tuples
Like lists, tuples that can hold any value are depicted using the {
and }
.
iex> {:ok, "hello"}
{:ok, "hello"}
iex> tuple_size({:ok, "hello"})
2
You should use the elem
and put_elem
to access and modify a tuple:
iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> elem(tuple, 1)
"hello"
iex> tuple_size(tuple)
2
iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> put_elem(tuple, 1, "world")
{:ok, "world"}
iex> tuple
{:ok, "hello"}
One very important use of tuple is to use them to return extra information from a function:
iex> Map.fetch(%{a: 1}, :a)
{:ok, 1}
iex> Map.fetch(%{a: 1}, :b)
:error
Keyword Lists
In Elixir, when a list contains 2-item tuples as values and the first value of the tuple is an atom, we call it a keyword list. A keyword list is a list, so every operator that can be used on a list can be used in the same manner:
iex> [{:otp_app, :hello_app}, {:deps, [...]}]
[otp_app: :hello_app, deps: [...]]
iex> [{:a, 1}, {:b, 2}]
[a: 1, b: 2]
And Elixir has another syntax to define such list:
iex> [otp_app: :hello_app, deps: [...]]
[otp_app: :hello_app, deps: [...]]
It's very common to find the keyword list in other functional languages. Below are characteristics of a keyword list:
- Keys must be atoms.
- Keys are ordered, as specified by the developer.
- Keys can be given more than once.
Closing
Remember that Elixir upholds the Immutability mantra of a functional language meaning that modifications made on a value return another copy of the value with the modifications without modifying the actual value in place.
Going forward, we will be visiting the Functions, Modules, and beautiful features that allow you concise and declarative code.