Behaviours in Elixir explained

Behaviours provide a way to define an interface which a module can implement. A module declares that it implements the Behaviour with the @behaviour annotation. The functions in the modules implementing the behaviour will be checked at compile time to see if they match the function specifications in the behaviour and if it doesn't it throws an error.

Behaviours provide a way to:

  • define a set of functions that have to be implemented by a module;
  • ensure that a module implements all the functions in that set.
Defining behaviours

If a module adopts the behaviour of another module, then it will have to define all the functions defined in the module that is said to behave.

So in order to define the function specifications that a module needs to implement the @callback directive is used

defmodule Greeter do
  @callback shen_says_hello(String.t) :: any
  @callback po_replies(String.t) :: any
end

Adopting a behaviour from another module

Modules adopting a behaviour will have to implement all the functions defined with the @callback directive.

# A module uses the @behaviour annotation to indicate that it implements a behaviour

defmodule LordShenGreetsPo do
  @behaviour Greeter
  def shen_says_hello(name) do
    IO.puts "Greetings, #{name}, we meet at last !!"
  end
  def po_replies(name) do
    IO.puts "Hey, how ya doin'?, #{name}"
  end
end


# Since the following module does not implement po_replies/1 a compile time warning will occur: "warning: undefined behaviour function po_replies/1 (for behaviour Greeter)"

defmodule LordShenGreetsPo do
  @behaviour Greeter
  def shen_says_hello(name) do
    IO.puts "Greetings, #{name}, we meet at last !!"
  end
end