Built-in protocols

Elixir ships with some built-in protocols. In previous chapters, we have discussed the Enum module which provides many functions that work with any data structure that implements the Enumerable protocol:

iex> Enum.map [1, 2, 3], fn(x) -> x * 2 end
[2,4,6]
iex> Enum.reduce 1..3, 0, fn(x, acc) -> x + acc end
6

Another useful example is the String.Chars protocol, which specifies how to convert a data structure with characters to a string. It’s exposed via the to_string function:

iex> to_string :hello
"hello"

Notice that string interpolation in Elixir calls the to_string function:

iex> "age: #{25}"
"age: 25"

The snippet above only works because numbers implement the String.Chars protocol. Passing a tuple, for example, will lead to an error:

iex> tuple = {1, 2, 3}
{1, 2, 3}
iex> "tuple: #{tuple}"
** (Protocol.UndefinedError) protocol String.Chars not implemented for {1, 2, 3}

When there is a need to “print” a more complex data structure, one can simply use the inspect function, based on the Inspect protocol:

iex> "tuple: #{inspect tuple}"
"tuple: {1, 2, 3}"

The Inspect protocol is the protocol used to transform any data structure into a readable textual representation. This is what tools like IEx use to print results:

iex> {1, 2, 3}
{1,2,3}
iex> %User{}
%User{name: "john", age: 27}

Keep in mind that, by convention, whenever the inspected value starts with #, it is representing a data structure in non-valid Elixir syntax. This means the inspect protocol is not reversible as information may be lost along the way:

iex> inspect &(&1+2)
"#Function<6.71889879/1 in :erl_eval.expr/5>"

There are other protocols in Elixir but this covers the most common ones.