|
| 1 | +# Behaviours |
| 2 | + |
| 3 | +Behaviours in Elixir (and Erlang) are a way to separate and abstract the generic part of a component (which becomes the *behaviour module*) from the specific part (which becomes the *callback module*). |
| 4 | + |
| 5 | +A behaviour module defines a set of functions and macros (referred to as *callbacks*) that callback modules implementing that behaviour must export. This "interface" identifies the specific part of the component. For example, the `GenServer` behaviour and functions abstract away all the message-passing (sending and receiving) and error reporting that a "server" process will likely want to implement from the specific parts such as the actions that this server process has to perform. |
| 6 | + |
| 7 | +If a callback module that implements a given behaviour doesn't export all the functions and macros defined by that behaviour, the user will be notified through warnings during the compilation process (no errors will happen). |
| 8 | + |
| 9 | +Elixir's standard library contains a few frequently used behaviours such as `GenServer`, `Supervisor`, and `Application`. |
| 10 | + |
| 11 | +## Defining a behaviour |
| 12 | + |
| 13 | +A behaviour is always backed by a module (which is how the behaviour will be identified): the module where callbacks are defined. To define a behaviour module, it's enough to define one or more callbacks in that module. To define callbacks, the `@callback` and `@macrocallback` module attributes can be used (for function callbacks and macro callbacks respectively). |
| 14 | + |
| 15 | + defmodule MyBehaviour do |
| 16 | + @callback my_fun(arg :: any) :: any |
| 17 | + @macrocallback my_macro(arg :: any) :: Macro.t |
| 18 | + end |
| 19 | + |
| 20 | +As seen in the example above, defining a callback is a matter of defining a specification for that callback, made of: |
| 21 | + |
| 22 | + * the callback name (`my_fun` or `my_macro` in the example) |
| 23 | + * the arguments that the callback must accept (`arg :: any` in the example) |
| 24 | + * the *expected* type of the callback return value |
| 25 | + |
| 26 | +For more information on typespecs, consult the ["Typespecs"](typespecs.html) page in the Elixir documentation. As mentioned in this page, type specification are only annotations used by documentation and tools, so defining such specifications for behaviours serves mostly for such purposes. |
| 27 | + |
| 28 | +### Optional callbacks |
| 29 | + |
| 30 | +Optional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules provide a default implementation for such callbacks in case the callback module does not implement them. Optional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a list of `{function_or_macro_name, arity}` tuples. For example: |
| 31 | + |
| 32 | + defmodule MyBehaviour do |
| 33 | + @callback vital_fun() :: any |
| 34 | + @callback non_vital_fun() :: any |
| 35 | + @macrocallback non_vital_macro(arg :: any) :: Macro.t |
| 36 | + @optional_callbacks non_vital_fun: 0, non_vital_macro: 1 |
| 37 | + end |
| 38 | + |
| 39 | +One example of optional callback in Elixir's standard library is `c:GenServer.format_status/2`. |
| 40 | + |
| 41 | +## Implementing behaviours |
| 42 | + |
| 43 | +To specify that a module implements a given behaviour, the `@behaviour` attribute must be used: |
| 44 | + |
| 45 | + defmodule MyBehaviour do |
| 46 | + @callback my_fun(arg :: any) :: any |
| 47 | + end |
| 48 | + |
| 49 | + defmodule MyCallbackModule do |
| 50 | + @behaviour MyBehaviour |
| 51 | + def my_fun(arg), do: arg |
| 52 | + end |
0 commit comments