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?