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?