jonnifyelixir
F3 · The Elixir Language / F3.06 · protocols

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

DISPATCH ON A VALUE TYPE def summarize(e), do: case e do %Course{} -> … %Lesson{} -> … %User{} -> … end one function · every type lives in it

[ 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

MECHANISM Protocol · dispatch on a value WHEN IT RESOLVES at runtime, from the value at compile time, on the module DISPATCH KEY the value __struct__ tag BUILT-IN EXAMPLES Enumerable, String.Chars, Inspect

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.

F3.06.1
Defining a protocol
defprotocol declares the contract; a call resolves to an implementation by the value's type, or raises Protocol.UndefinedError.
F3.06.2
Implementing for a struct
One defimpl per type builds a dispatch table; new types are added without touching the protocol or the other implementations.
F3.06.3
Behaviours & callbacks
@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

Related in this course