Implementing Any

Manually implementing protocols for all structs can quickly become repetitive and tedious. In such cases, Elixir provides two options: we can explicitly derive the protocol implementation for our types or automatically implement the protocol for all types. In both cases, we need to implement the protocol for Any.

Deriving

Elixir allows us to derive a protocol implementation based on the Any implementation. Let’s first implement Any as follows:

defimpl Blank, for: Any do
  def blank?(_), do: false
end

Now, when defining the struct, we can explicitly derive the implementation for the Blank protocol. Let’s create another struct, this one called DeriveUser:

defmodule DeriveUser do
  @derive Blank
  defstruct name: "john", age: 27
end

When deriving, Elixir will implement the Blank protocol for DeriveUser based on the implementation provided for Any. Note this behaviour is opt-in: structs will only work with the protocol as long as they explicitly implement or derive it.

Fallback to Any

Another alternative to @derive is to explicitly tell the protocol the fallback to Any when an implementation cannot be found. This can be achieved by setting @fallback_to_any to true in the protocol definition:

defprotocol Blank do
  @fallback_to_any true
  def blank?(data)
end

Assuming we have implemented Any as in the previous section:

defimpl Blank, for: Any do
  def blank?(_), do: false
end

Now all data types (including structs) that we have not implemented the Blank protocol will be considered non-blank. In contrast to @derive, falling back to Any is opt-out: all data types get a pre-defined behaviour unless they provide their own implementation of the protocol. Which technique is best depends on the use case but, given Elixir developers prefer explicit over implicit, you may see many libraries pushing towards the @derive approach.