Protocols

  1. Protocols and structs
  2. Implementing Any
    1. Deriving
    2. Fallback to Any
  3. Built-in protocols
  4. Protocol consolidation

Protocols are a mechanism to achieve polymorphism in Elixir. Dispatching on a protocol is available to any data type as long as it implements the protocol. Let’s see an example.

In Elixir, only false and nil are treated as false. Everything else evaluates to true. Depending on the application, it may be important to specify a blank? protocol that returns a boolean for other data types that should be considered blank. For instance, an empty list or an empty binary could be considered blanks.

We could define this protocol as follows:

defprotocol Blank do
  @doc "Returns true if data is considered blank/empty"
  def blank?(data)
end

The protocol expects a function called blank? that receives one argument to be implemented. We can implement this protocol for different Elixir data types as follows:

# Integers are never blank
defimpl Blank, for: Integer do
  def blank?(_), do: false
end

# Just empty list is blank
defimpl Blank, for: List do
  def blank?([]), do: true
  def blank?(_),  do: false
end

# Just empty map is blank
defimpl Blank, for: Map do
  # Keep in mind we could not pattern match on %{} because
  # it matches on all maps. We can however check if the size
  # is zero (and size is a fast operation).
  def blank?(map), do: map_size(map) == 0
end

# Just the atoms false and nil are blank
defimpl Blank, for: Atom do
  def blank?(false), do: true
  def blank?(nil),   do: true
  def blank?(_),     do: false
end

And we would do so for all native data types. The types available are:

  • Atom
  • BitString
  • Float
  • Function
  • Integer
  • List
  • Map
  • PID
  • Port
  • Reference
  • Tuple

Now with the protocol defined and implementations in hand, we can invoke it:

iex> Blank.blank?(0)
false
iex> Blank.blank?([])
true
iex> Blank.blank?([1, 2, 3])
false

Passing a data type that does not implement the protocol raises an error:

iex> Blank.blank?("hello")
** (Protocol.UndefinedError) protocol Blank not implemented for "hello"