Elixir

Elixir Basics - 3. Tuples

Updated:

Tuples in Elixir, like lists, can hold any value. They are created with curly brackets {}.

iex(1)> {"Hello", :true, 5.43}
{"Hello", true, 5.43}

Tuples vs Lists

However, unlike lists, the elements within a tuple are stored contiguously in memory. This means that you can access an element within a tuple via its index.

iex(2)> tuple = {"Hello", :true, 5.43}
{"Hello", true, 5.43}
iex(3)> elem(tuple, 2)
5.43

This also means that getting the size of a tuple is an inexpensive operation. Whereas with lists, it is an expensive operation.

iex(4)> tuple = {"Hello", :true, 5.43}
{"Hello", true, 5.43}
iex(5)> tuple_size(tuple)
3

Since lists are not stored continugously in memory, getting the size of a list is an expensive operation as the entire list chain has to be traversed, one element at a time, until the last element is found.

Adding Elements

Elements can be added to a tuple at a particular index by using the put_elem/3 function.

iex(6)> tuple = {"Hello", :true, 5.43}
{"Hello", true, 5.43}
iex(7)> put_elem(tuple, 2, 14)
{"Hello", true, 14}

Remember, that what is returned is a new tuple, the original tuple has not been modified because Elixir has immutable data structures.

iex(6)> tuple = {"Hello", :true, 5.43}
{"Hello", true, 5.43}
iex(7)> put_elem(tuple, 2, 14)
{"Hello", true, 14}
iex(8)> tuple
{"Hello", true, 5.43}

Common Use Cases

Tuples are often used in Elixir to return extra information from functions. For example, when using the File.read/1 function a tuple is returned where the first element is an atom letting you know if the operation was successful or not.

  • If it is, the first element will be the atom :ok and then the contents of the file.
  • If not, the first element will be the atom :error and then the reason for the error.
iex(10)> h File.read/1

Returns {:ok, binary}, where binary is a binary data object that contains the
contents of path, or {:error, reason} if an error occurs.

Typical error reasons:

:enoent  - the file does not exist
:eacces  - missing permission for reading the file, or for searching
    one of the parent directories
:eisdir  - the named file is a directory
:enotdir - a component of the file name is not a directory; on some
    platforms, :enoent is returned instead
:enomem  - there is not enough memory for the contents of the file

Length vs Size

In Elixir when counting elements within a data structure, the language differentiates between length and size. A function is named:

  • size when the value is pre-calculated, like with Tuples, or
  • length when the operation is linear like with Lists.

This means that getting the size of a data structure is an inexpensive operation while getting the length of a data structure is an expensive operation.

Size

For example, getting the size of a Tuple is an inexpensive operation.

iex(4)> tuple = {"Hello", :true, 5.43}
{"Hello", true, 5.43}
iex(5)> tuple_size(tuple)
3

Remember, the reason this is inexpensive is because the size of the Tuple is already known since the elements are stored contiguiously in memory.

Length

Getting the length of a List an expensive operation.

iex(12)> list = ["Hello", :true, 5.43]
["Hello", true, 5.43]
iex(13)> length(list)
3

Remember, the reason this is expensive is because the elements are not stored contiguiously in memory. The more elements there are in the list, the more expensive this operation becomes.

Sources

Previous
2. Lists