Behaviours in Elixir
| Define callbacks | |
| Adopt one | |
| Compiler checks | |
| GenServer is a behaviour (preview) |
Define callbacks
A behaviour lists function contracts that adopter modules must fulfil. Each contract is a callback annotation with a name, argument types, and a return type.
defmodule Printer do
@callback print(term) :: String.t()
end
Printer demands one print function that takes any term and returns text. The annotation never runs, it only records the contract for the compiler.
Adopt one
A module adopts a behaviour with the behaviour annotation and then defines every listed callback. From that point the compiler links the module to the contract.
defmodule Laser do
@behaviour Printer
def print(text) do
"laser: " <> text
end
end
Laser.print applied to a greeting returns a tagged string, and the behaviour annotation documents that Laser plays the Printer role. Callers can now accept any Printer module with confidence.
Compiler checks
The compiler compares each adopter against its contracts and warns about gaps. A missing function, a wrong arity, or a mistyped name shows up at compile time instead of hiding until the code runs.
defmodule Broken do
@behaviour Printer
end
Broken defines no print function, so compiling it warns that the Printer callback is missing. Treat behaviour warnings as errors during study and fill in every callback before moving on.
GenServer is a behaviour (preview)
Behaviours power the OTP framework behind long lived Elixir services. GenServer is the famous example: it handles processes, messages, and restarts, while you supply small callbacks such as init.
defmodule Counter do
use GenServer
def init(count) do
{:ok, count}
end
end
Counter asks GenServer for all process machinery and only teaches it how to start from a count. Later lessons build a full server on this pattern, so remember that use plus callbacks shape every OTP module.
Next: The pipe operator in Elixir
Article author: Arthur Isaev