Elixir Behaviours

Welcome to a tutorial on Behaviors in Elixir. 

In Elixir, Behaviors are a way to separate and abstract the generic part of a component (i.e the behavior module) from the specific part (i.e the callback module). Behaviors provide ways to do the following:

To define a set of functions that have to be implemented by a module.

To ensure that a module implements all the functions in that set.

Also, you can think of behaviors to be like interfaces in object-oriented languages such as Java; or a set of function signatures that a module has to implement.

 

Defining a Behaviour

We will consider an example of how to create our own behavior and then use this generic behavior to create a module. We are going to define a behavior that greets people hello and goodbye in different languages.

defmodule GreetBehaviour do
   @callback say_hello(name :: string) :: nil
   @callback say_bye(name :: string) :: nil
end

The @callback directive is typically used to list the functions that adopting modules will need to define. Also, it specifies the number of arguments, their type, and their return values.

 

Adopting a Behaviour

In the above session, we defined a behavior successfully. So, let’s adopt and implement it in multiple modules. We will create two modules implementing this behavior in English and Spanish. This is shown below.

defmodule GreetBehaviour do
   @callback say_hello(name :: string) :: nil
   @callback say_bye(name :: string) :: nil
end

defmodule EnglishGreet do
   @behaviour GreetBehaviour
   def say_hello(name), do: IO.puts("Hello " <> name)
   def say_bye(name), do: IO.puts("Goodbye, " <> name)
end

defmodule SpanishGreet do
   @behaviour GreetBehaviour
   def say_hello(name), do: IO.puts("Hola " <> name)
   def say_bye(name), do: IO.puts("Adios " <> name)
end

EnglishGreet.say_hello("Alex")
EnglishGreet.say_bye("Alex")
SpanishGreet.say_hello("Alex")
SpanishGreet.say_bye("Alex")

The output is:

Hello Alex
Goodbye, Alex
Hola Alex
Adios Alex

From the above example, you can see we adopted a behavior by using the @behaviour directive in the module. 

Also, we had to define all the functions implemented in the behaviour for all the child modules. However, this can roughly be considered equivalent to interfaces in OOP languages.