🎓 A1Learner
🔍
0 of 54 lessons completed

Elixir Protocols

A protocol is a shared function name that different types can each implement in their own way. A call with that name runs the version that matches the type of the value passed in.

Measure text through one shared name

Sized promises a size function. The BitString version measures text with String.length.

defprotocol Sized do
  def size(data)
end

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

IO.puts(Sized.size("hello"))
IO.puts(Sized.size("Elixir"))

The same name measures a list

The List version counts items with length. The call looks identical and the type of the argument picks the version.

defprotocol Sized do
  def size(data)
end

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

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

IO.puts(Sized.size("hello"))
IO.puts(Sized.size([10, 20, 30]))

A struct gets its own version

The Box version matches the struct inside its function. It counts the items stored in the box.

defmodule Box do
  defstruct items: []
end

defprotocol Sized do
  def size(data)
end

defimpl Sized, for: Box do
  def size(%Box{items: items}), do: length(items)
end

box = struct(Box, items: [10, 20, 30, 40])
IO.puts(Sized.size(box))

Example

defmodule Box do
  defstruct items: []
end

defprotocol Sized do
  def size(data)
end

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

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

defimpl Sized, for: Box do
  def size(%Box{items: items}), do: length(items)
end

box = struct(Box, items: [10, 20])
IO.puts(Sized.size("hello"))
IO.puts(Sized.size([10, 20, 30]))
IO.puts(Sized.size(box))

Key points

  • defprotocol: defprotocol names the protocol and lists the functions it promises.
  • defimpl: defimpl writes the version of the function for one named type.
  • Dispatch: A protocol call picks the implementation that matches the type of its argument.
  • BitString: Text values are BitStrings, so a string implementation can measure text with String.length.
  • Own types: A struct can have its own implementation, written for its module name.

In this example, one protocol named Sized promises a single size function. Three implementations cover text, a list, and the Box struct, and each call runs the version that matches its argument.

Note

One call site can handle many types because each type supplies its own implementation.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

With the Sized implementations from this lesson, what does Sized.size([10, 20]) return?