F3 · Data & shape · module 6
Polymorphism: protocols & behaviours
A struct carries its module in the __struct__ tag, and F3.05 matched on
that tag by hand. Elixir turns the same idea into a language feature two ways. A protocol
dispatches a function to a different implementation depending on a value's type, at runtime. A
behaviour is a contract a module promises to fulfil, checked at compile time.
The portal needs both: one summarize/1 that reads any entity, and a
Notifier contract that email and SMS modules each satisfy. This module separates the
two mechanisms, then takes each apart.
Adding a type: closed for editing
[ Course · Lesson · User ]
A new type means reopening this one function.
Two kinds of polymorphism
The question that separates them: does the behaviour vary by the value passed in, or by the module doing the work. A protocol answers the first — pick the implementation from the value's type. A behaviour answers the second — a module declares it implements a contract. Choose what varies and see which mechanism fits.
What varies · select one
Both are polymorphism: one function name, many behaviours. The split is when and on what the choice is made — a protocol on a value at runtime, a behaviour on a module at compile time.
Three deep dives
Three pages in order: how a protocol call resolves to an implementation, writing those implementations per struct, then the behaviour as the compile-time counterpart.
defprotocol declares the contract; a call resolves to an implementation by the value's type, or raises Protocol.UndefinedError.defimpl per type builds a dispatch table; new types are added without touching the protocol or the other implementations.@callback declares the contract, @behaviour and @impl fulfil it — the compile-time counterpart that OTP is built on.F3.05 · the __struct__ tag
A struct carries its module in a tag, and a pattern can match on it — dispatch by type, written by hand.
F3 · protocol dispatch
The same dispatch as a language feature: one call, an implementation chosen from the tag, extensible per type.
Start with defining a protocol, then implementing it per struct, then behaviours and callbacks. Next module: F3.07 — Processes & the actor model, where modules become running, message-passing units.
References
Primary sources for this lesson, and where it connects in the course.
Sources
- Protocols — Elixir documentation — polymorphism by data type.
Protocol— Elixir documentation — defining and consolidating protocols.- Typespecs and behaviours — Elixir documentation — contracts via behaviours.
Related in this course
- F3.05 · Structs, maps & keyword lists — the
__struct__tag dispatch builds on. - F3.04 · Enumerables & streams —
Enumerable, the canonical protocol. - F3.08 · OTP: GenServer & supervisors — behaviours in practice.