How does protocol dispatch work?

This does only explain it roughly, but should be just enough to understand it.

  1. Kernel.to_string/1 is a macro, expanding to String.Chars.to_string/1
  2. String.Chars.to_string/1 matches on its argument, and without protocol consolidation it dispatches to String.Chars.xxx.to_string/1 where xxx is the qualified alias of the struct or elixirs internal type. With consolidation those xxx implementations are integrated directly into String.Chars.to_string/1.

With consolidation it might look like this (simplified):

defmodule String.Chars do
  def to_string(list) when is_list(list), do: List.to_string(list)
  def to_string(%Foo{bar: bar}), do: "#Foo<bar: #{bar}>"
end

without consilidation more like this:

defmodule String.Chars do
  def to_string(list) when is_list(list), do: List.to_string(list)
  def to_string(%struct{} = item), do: :"Elixir.#{__MODULE__}.#{struct}" |> apply(:to_string, [item])
end
2 Likes