Why are behaviour methods referred to as "callbacks"?

In simple terms the “behaviour” already exists as the behaviour module capturing the generic parts. You are implementing the callback module which contains the specific parts. To execute those specific parts the behaviour module calls the “callback” functions on the callback module.

The behaviour module is passed a callback module much in the same way a function is passed a callback function - the difference is that the behaviour module expects certain functions to be implemented by the callback module rather than there just being that one function.

defmodule Parser do
  @callback parse(String.t) :: {:ok, term} | {:error, String.t}
  @callback extensions() :: [String.t]

  def parse!(callback_module, contents) do
    case callback_module.parse(contents) do
      {:ok, data} -> data
      {:error, error} -> raise ArgumentError, "parsing error: #{error}"
    end
  end
end

I swapped implementation with callback_module - so it makes sense that callback_module.parse/1 is a callback function.

Another example from the Access behaviour

 def fetch(%module{} = container, key) do
    module.fetch(container, key)
  rescue
    exception in UndefinedFunctionError ->
      raise_undefined_behaviour(exception, module, {^module, :fetch, [^container, ^key], _})
  end

The fetch/2 function implemented by Access grabs the callback module from the struct so it can turn around and call the module.fetch/2 callback function.

With behaviours you are composing the callback module with the behaviour module - there is no inheritance.

11 Likes