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.