We have used the inspect function many times in this book. It returns a printable representation of any value as a binary (which is what we hard-core folks call strings).
But stop and think for a minute. Just how can Elixir, which doesn’t have objects, know what to call to do the conversion to a binary? You can pass inspect anything, and Elixir somehow makes sense of it.
It could be done using guard clauses:
| def inspect(value) when is_atom(value), do: ... |
| def inspect(value) when is_binary(value), do: ... |
| : : |
But there’s a better way.
Elixir has the concept of protocols. A protocol is a little like the behaviours we saw in the previous chapter in that it defines the functions that must be provided to achieve something. But a behaviour is internal to a module—the module implements the behaviour. Protocols are different—you can place a protocol’s implementation completely outside the module. This means you can extend modules’ functionality without having to add code to them—in fact, you can extend the functionality even if you don’t have the modules’ source code.