
Understanding immutability
In Elixir, data, once created, is immutable. Whenever some input is passed into a function to be transformed, the original value remains unchanged and a new value is created.
This allows for safe concurrent access to the same data by n processes. It makes concurrency easier to manage, as it is guaranteed that no process can change the original data. Any transformation on the original data will result in new data being created.
Getting ready
To get started, we need to follow these steps:
- Create a file, which is
transformator.ex
, defining theTransformator
module by adding the following code:defmodule Transformator do @default_list [1,2,3,4,5,6] def get_odd_numbers(list \\ @default_list) do Enum.filter(list, fn(x)-> rem(x,2) == 1 end) end def get_even_numbers(list \\ @default_list) do Enum.filter(list, fn(x)-> rem(x,2) == 0 end) end end
- Start an IEx session in your console:
>iex
- Compile the
Transformator
module:iex(1)> c("transformator.ex") [Transformator]
How to do it…
To demonstrate the immutability of data, we will follow these steps using our IEx session:
- Create a list called
original
:iex(2)> original = [1, 2, 3, 4, 5, 6, 7, 8, 9]
- Pass the
original
list into theget_odd_numbers
function ofTransformator
, assigning the result toodd
:iex(.3)> odd = Transformator.get_odd_numbers(original) [1, 3, 5, 7, 9]
- Pass the
original
list into theget_even_numbers
function ofTransformator
, assigning the result toeven
:iex(4)> even = Transformator.get_even_numbers(original) [2, 4, 6, 8]
- Apply the
foldl
function to theodd
,even
, andoriginal
lists to return the sum of all elements in each list:iex(5)> List.foldl(original, 0, fn (x, acc) -> x + acc end) 45 iex(6)> List.foldl(odd, 0, fn (x, acc) -> x + acc end) 25 iex(7)> List.foldl(even, 0, fn (x, acc) -> x + acc end) 20
Note
The
List.foldl/3
function reduces the given list towards the left with a function. We pass the list we want to reduce, an accumulator, and the function we wish to apply.In this case, we pass each of the lists, an accumulator with the initial value of 0, and sum each element of the list with the accumulator.
- We will now take each of the lists and shuffle them to change the order of their elements:
iex(8)> Enum.shuffle(original) [3, 7, 2, 8, 6, 4, 9, 1, 5] iex(9)> Enum.shuffle(odd) [7, 1, 5, 9, 3] iex(10)> Enum.shuffle(even) [2, 6, 8, 4]
- Verify each list to see that it has not changed:
iex(11)> even [2, 4, 6, 8] iex(12)> odd [1, 3, 5, 7, 9] iex(13)> original [1, 2, 3, 4, 5, 6, 7, 8, 9]
How it works…
In steps 2 and 3, we pass our data structure (the original
list) into functions that filter that data structure, and in step 4, we take our lists and reduce them by summing all their values. All these transformations occur without changing any of the original data. In step 5, immutability becomes clearer as we actually pass the lists into a function that potentially changes the order of its elements and yet that change is made by taking the original data, copying it, and creating new lists. As we can see in the final step, the input data has not changed.
Note
If you use values greater than 65 in the input lists for the functions defined in the Transformator
module, you might be surprised with the output you get in IEx. You could try the following:
iex(1)> Transformator.get_even_numbers([65,66,67,68,69,70]) 'BDF'
The output, which is BDF
, is IEx interpreting the resulting list [66, 68, 70] as a character list, where 66 is the ASCII value for B, 68 for D, and 70 for F.