Behaviours are about modules, Protocols are about data.
Behaviour
Is a list of functions that a module has. It’s useful when you’re doing something and need to say “now I need you to do your bit”.
An example of a behaviour is Plug . When running middlewear on a webserver, it says “OK, now you do your bit to handle this request” for each plug that’s been set up.
You implement behaviours by defining the required functions in a module, and use them by passing that module name into something that expects to be able to call the functions in the behaviour.
Protocols
Is way of doing something with a type of data. It’s useful when you have some data and need to say “I want to be able to do X with this”.
An example of a protocol is String.Chars. It says “this is the way to convert data to a string”. This is used by to_string
.
You implement protocols by declaring the implementation for a specific datatype, and use them by passing data into a function that expects to be able to use the protocol for that data.
Here’s an example of a behaviour:
defmodule AnimalBehaviour do
@callback make_sound() :: atom()
def hello(callback_module), do: callback_module.make_sound()
end
defmodule Dog do
@behaviour AnimalBehaviour
@impl AnimalBehaviour
def make_sound, do: :woof
end
And a protocol:
defprotocol AnimalProtocol do
def hello(data)
end
defmodule Cat do
defstruct []
defimpl AnimalProtocol do
def hello(%Cat{}), do: :meow
end
end
Usage:
iex(1)> AnimalBehaviour.hello(Dog)
:woof
iex(2)> AnimalProtocol.hello(%Cat{})
:meow