Data Types


Elixir has all of the basic data types one would expect from a general-purpose language. Many of these types will be explored in greater detail in the chapters that follow. For now, let's acquaint ourselves with the basic data types of Elixir.

We will also be taking advantage of several predicate methods to check value type. The methods use the syntax is_<datatype>/1where <datatype> is the type of data we are checking and /1 represents the number of expected arguments.

Numbers

Numbers in Elixir are divided into two categories, "Integers" and "Floating points".

Integers

Integers are countable numbers. They can be positive or negative. Some examples of integers are -44, -2, 0, 1, 2, 3, 95, 599. We can verify this is true by starting an iex session and using the predicate method is_integer/1.

iex(1)> is_integer(1)
true
iex(2)> is_integer(-44)
true
iex(3)> is_integer(10098)
true
# Elixir can use underscores to make integers more readable
iex(4)> is_integer(10_098)
true
iex(5)> is_integer(0)
true

Remember, integers are countable and thus, 3.14, for example, is not of type integer. Any number that consists of a decimal part is considered a float.

Floats

A floating point number, float for short, is simply any number that contains a decimal. Therefore, 1.5, 3.14, and 5.0 are all examples of floats. We will again verify this in iex.

iex(1)> is_float(3.14)
true
iex(2)> is_float(5.0)
true
iex(3)> is_float(0.0000001)
true

Note: the return value of an operation between an integer and float will always be a float.

# Multiply an integer and float
iex(1)> 4 * 4.0
16.0

# Divide an integer and float
iex(2)> 20 / 5.0
4.0

Strings

Strings are a series of UTF-8 encoded characters surrounded by double quotes. Examples of strings are, "hello", "this is a string", and "this is a slightly longer string". Once again, let's jump into an iex session and see what we can find out about the string data type. This time we will try inspecting the output with the built-in i method.

iex(1)> i "hello"
Term
  "hello"
Data type
  BitString
Byte size
  5
Description
  This is a string: a UTF-8 encoded binary. It's printed surrounded by
  "double quotes" because all UTF-8 encoded codepoints in it are printable.
Raw representation
  <<104, 101, 108, 108, 111>>
Reference modules
  String, :binary
Implemented protocols
  IEx.Info, Collectable, Inspect, List.Chars, String.Chars

Elixir provides a generous inspect method. The output contains our term with the corresponding data type, description, and even reference modules. This method will be helpful for debugging later.

Atoms

An atom is a constant whose name is also its value. Atoms are preceded by a colon ( : ) character, making them easy to recognize. They are used in favor of strings due to their memory efficiency. Examples of atoms are :ok, :fallback_controller, :success. Atoms are the equivalent of symbols for those who are familiar with the Ruby programming language.

Booleans

The boolean values true and false are just representations of the atoms :true and :false. Elixir's boolean logic is rather straightforward. Both false and nil will return false, everything else will return true. Elixir will return true to verify a boolean value using, is_boolean/1.

Lists

Lists are composed of an ordered set of elements. The elements are enclosed in [ ] brackets and separated by commas. They may contain elements of any data type. For example, [ :ok, "Logger", 22 ] , is a list composed of three different data types, an atom, string, and integer. It's important to note that lists in Elixir are also called "linked-lists", which means each element is internally represented as [ head | tail ] . This special syntax " | " is called the cons operator, short for "list constructor". In Elixir, the head of a list is the first element and the tail is a list of the remaining elements (or an empty list if the list contained only a single element). Let's start an iex session to see this in action.

iex(1)> [ head | tail ] = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

iex(2)> head
1

iex(3)> tail
[2, 3, 4, 5]

The "head | tail" notion was created for the purpose of recursive processing, an important concept in functional programming. However, this also means that the time it takes to traverse a list is proportional to the size of the list itself. For this reason, it's common to see items prepended to lists rather than appended. Prepending a new element to a list requires little processing, whereas appending a new element to the end of a list requires traversing the entire list. While the benefits of linked-lists may not be apparent at first, they are a well suited structure in the arsenal of any Elixirist.

There are two built-in functions for retrieving the "head" and "tail" of a list. They are hd and tl for the head and tail, respectively. This means that for any Elixir list, we can retrieve the first element by passing the list to hd and the last element by passing the list to tl. Here is an example.

iex(1)> list = [1,2,3,4,5]
[1, 2, 3, 4, 5]

iex(2)> hd list
1

iex(3)> tl list
[2, 3, 4, 5]

Tuples

Tuples let you combine multiple items into a single fixed sized collection. They can contain any type of data enclosed in curly braces { } , where the elements are separated by commas. Tuples are generally best suited for storing a few elements, usually four or less. To store a larger collection of elements Elixirists will reach for a list. You can retrieve the values of items with the elem function, set values in a new tuple with the put_elem function, and find out how many items are in a tuple with the tuple_size function.

Passing a single tuple rather than a pile of arguments gives Elixir much of its flexibility, especially when you get to passing messages between different processes. For now, it's only important to recognize that a tuple is a collection of elements implemented with contiguous areas of memory. This means that accessing elements can be achieved much quicker than with lists.

Keyword Lists

A keyword list is an associative data structure, for example, a key/value store. They are composed of two element tuples, where the first element (the key) is an atom. Let's see what they look like in iex:

# A list of tuples
iex(1)> [{:ok, "success"}, {:error, "failure"}]
[ok: "success", error: "failure"]

# shorthand syntax
iex(2)> [:ok, "success", :error, "failure"]
[:ok, "success", :error, "failure"]

Keyword lists are useful as they are commonly used along with pattern matching to pass options to functions. It's important to note that the keys must be atoms.

Maps

Maps are a collection of key/value pairs. They are defined with the %{ } syntax. Unlike keyword lists, maps do not support duplicate keys. If a duplicate key is added it will replace the current key/value pair. Let's open an iex session and create some maps.

# Construct a map with the %{ } syntax
iex(1)> %{name: "Robert", age: 74}
%{age: 74, name: "Robert"}

Here we constructed a map with two keys, name and age. Because we are using atoms as the keys we can use the above syntax, appending the " : " colon to the atom and surrounding the value, which is a string, in double quotes. There is an alternative syntax available to us, the => sign. Think of this sign, the fat arrow, as meaning "maps to". So for example:

# A map with 2 keys, a maps to 1, b maps to 2
iex(1)> %{"a"=> 1, "b" => 2}
%{"a" => 1, "b" => 2}

We will often want to store the map in a variable so that we can perform some function:

iex(1)> actor = %{name: "Robert", age: 74}
%{age: 74, name: "Robert"}
iex(2)> actor.name
"Robert"

results matching ""

    No results matching ""