🎓 A1Learner
🔍
0 of 46 lessons completed

Elixir Protocol Consolidation

Protocol consolidation is the step that bakes protocol implementations into the protocol module at compile time. It speeds up dispatch in a compiled project, while a plain script stays unconsolidated.

A script protocol is not consolidated

Sized has implementations for text and lists. Both calls still dispatch to the right implementation.

defprotocol Sized do
  def size(data)
end

defimpl Sized, for: BitString do
  def size(s), do: String.length(s)
end

defimpl Sized, for: List do
  def size(l), do: length(l)
end

IO.inspect(Sized.size("hello"))
IO.inspect(Sized.size([1, 2, 3]))
IO.inspect(Protocol.consolidated?(Sized))

Dispatch chooses an implementation for each value

impl_for names the implementation for a value. It returns nil when no implementation exists.

defprotocol Sized do
  def size(data)
end

defimpl Sized, for: BitString do
  def size(s), do: String.length(s)
end

defimpl Sized, for: List do
  def size(l), do: length(l)
end

IO.inspect(Sized.impl_for("hello"))
IO.inspect(Sized.impl_for([1, 2]))
IO.inspect(Sized.impl_for(42))

A later implementation is picked up

Sized first has only a list implementation. A tuple implementation defined later works at once.

defprotocol Sized do
  def size(data)
end

defimpl Sized, for: List do
  def size(l), do: length(l)
end

IO.inspect(Sized.size([1, 2, 3]))

defimpl Sized, for: Tuple do
  def size(t), do: tuple_size(t)
end

IO.inspect(Sized.size({:a, :b}))
IO.inspect(Sized.size([1, 2, 3]))
IO.inspect(Protocol.consolidated?(Sized))

Example

defprotocol Sized do
  def size(data)
end

defimpl Sized, for: BitString do
  def size(s), do: String.length(s)
end

defimpl Sized, for: List do
  def size(l), do: length(l)
end

defimpl Sized, for: Tuple do
  def size(t), do: tuple_size(t)
end

IO.inspect(Sized.size("hello"))
IO.inspect(Sized.size([10, 20]))
IO.inspect(Sized.size({:a, :b, :c}))
IO.inspect(Protocol.consolidated?(Sized))

Key points

  • Consolidation: it replaces a runtime lookup with implementations stored in the protocol module.
  • Script rule: a protocol defined in a plain script is not consolidated.
  • Dispatch: an unconsolidated protocol still dispatches to the right implementation for each value.
  • Lookup: impl_for returns the implementation module for a value, or nil when no implementation exists.
  • Later implementation: a new implementation defined later in a script is picked up by later calls.

In this example, Sized gains implementations for text, lists, and tuples, and each call dispatches to the matching one. The final check is false, so this script protocol is still unconsolidated.

Note

a compiled project can consolidate protocols, while a plain script cannot show that step.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

In a plain script, what does Protocol.consolidated?(Sized) return for a protocol defined in that script?