Protocols and structs
The power of Elixir’s extensibility comes when protocols and structs are used together.
In the previous chapter, we have learned that although structs are maps, they do not share protocol implementations with maps. Let’s define a User
struct as in that chapter:
iex> defmodule User do
...> defstruct name: "john", age: 27
...> end
{:module, User,
<<70, 79, 82, ...>>, {:__struct__, 0}}
And then check:
iex> Blank.blank?(%{})
true
iex> Blank.blank?(%User{})
** (Protocol.UndefinedError) protocol Blank not implemented for %User{age: 27, name: "john"}
Instead of sharing protocol implementation with maps, structs require their own protocol implementation:
defimpl Blank, for: User do
def blank?(_), do: false
end
If desired, you could come up with your own semantics for a user being blank. Not only that, you could use structs to build more robust data types, like queues, and implement all relevant protocols, such as Enumerable
and possibly Blank
, for this data type.