Help understanding protocols and behaviours

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 your example implemented with 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 with 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
14 Likes