Erlang basics · Lesson 22 (open contents)
Define a module contract
Declare a callback and implement it in a separate module.
Run this first
Run it once, change one input, and compare the new result.
%% greeter.erl declares the contract
-module(greeter).
-callback greet(binary()) -> binary().
%% friendly.erl implements it
-module(friendly).
-behaviour(greeter).
-export([greet/1]).
greet(Name) -> <<"Hello, ", Name/binary>>.- After compiling both modules,
friendly:greet(<<"Maya">>)returns<<"Hello, Maya">>.
Read from the first line down
- Read
-callback: Declare one required function signature. - Read
-behaviour(Module).: State which contract this module implements. - Read
-export([greet/1]).: Make the callback callable.
Symbols are not secret signs
-callbackDeclare one required function signature.
-behaviour(Module).State which contract this module implements.
-export([greet/1]).Make the callback callable.
Match each name to its meaning
behaviour
A behaviour lists callback functions that implementing modules promise to export.
callback
A callback specification names the arguments and return type required by the contract.
implementation
The behaviour attribute asks the compiler to warn when callbacks are missing.
Why these forms are useful
Run the example first. Predict one result, then change one input and run it again.
A behaviour lists callback functions that implementing modules promise to export.
A callback specification names the arguments and return type required by the contract.
Why this shape?
Why does a behaviour define callbacks without creating a process?
A behaviour first states which functions a module must implement. GenServer/gen_server is a behaviour with a runtime protocol, but a general behaviour starts nothing by itself.
It standardizes a boundary. It does not choose state ownership, supervision, capacity, or error policy for you.
Coming from Java, Python, or JavaScript
Java
- Familiar starting point
- An interface defines a method contract.
- What BEAM changes
- A behaviour constrains module/function/arity entries, which callers still invoke as module functions.
- False friend
- Implementing one creates neither an object nor a thread.
Python
- Familiar starting point
- An ABC or Protocol.
- What BEAM changes
- Callback metadata helps tools check an implementation and lets OTP invoke it.
- False friend
- It is not a decorator that wraps runtime calls.
JavaScript
- Familiar starting point
- A conventional object shape or TypeScript interface.
- What BEAM changes
- A behaviour lives at the BEAM module and callback-entry level.
- False friend
- A type contract and a process lifecycle remain separate decisions.
Close the answer and try
Add the behaviour attribute to another module.
-module(formal).
____
-export([greet/1]).Target result: Declare greeter as the behaviour.
Stuck? Read one hint
Use the -behaviour(...) attribute.
After you run it, see one answer
-module(formal).
-behaviour(greeter).
-export([greet/1]).Think about it: Does a behaviour start a process?
No. It is a module contract. OTP behaviours add process patterns in later lessons.
Remember these three lines
- 1
Behaviours declare contracts.
- 2
Callbacks need exported implementations.
- 3
A generic behaviour does not imply concurrency.