DoubleDown.BehaviourFacade (double_down v0.47.2)

Copy Markdown View Source

Generates a dispatch facade for a vanilla Elixir @behaviour module.

Use this when you want DoubleDown's dispatch machinery for a behaviour you don't control — a third-party library behaviour, an existing @behaviour in your codebase, or any module that defines @callback declarations without using defcallback.

For behaviours you do control, prefer DoubleDown.ContractFacade with defcallback — it gives you richer features (pre_dispatch transforms, @doc tag sync, combined contract + facade in one module).

Usage

defmodule MyApp.Todos do
  use DoubleDown.BehaviourFacade,
    behaviour: MyApp.Todos.Behaviour,
    otp_app: :my_app
end

The behaviour module must be compiled in a prior compilation unit — its .beam file must be on disk before the facade compiles. In a Mix project, this means the behaviour and facade must be in separate elixirc_paths directories (e.g. behaviour in lib/ or an earlier test support directory, facade in a later one). Combined contract + facade in a single module is not supported — use DoubleDown.ContractFacade for that.

Options

  • :behaviour (required) — the vanilla behaviour module to generate a facade for. Must define @callback declarations.
  • :otp_app (required) — the OTP application name for config-based dispatch. Implementations are resolved from Application.get_env(otp_app, behaviour)[:impl].
  • :test_dispatch? — same as DoubleDown.ContractFacade. Defaults to Mix.env() != :prod.
  • :static_dispatch? — same as DoubleDown.ContractFacade. Defaults to Mix.env() == :prod.

Param names

Where @callback declarations use annotated types like id :: String.t(), the annotation name is used as the facade function's parameter name. For bare types like String.t(), parameter names are synthesized as arg1, arg2, etc.

Configuration

# config/config.exs
config :my_app, MyApp.Todos.Behaviour, impl: MyApp.Todos.Impl

Testing

setup do
  DoubleDown.Testing.set_fn_handler(MyApp.Todos.Behaviour, fn
    :get_item, [id] -> {:ok, %{id: id}}
    :list_items, [] -> []
  end)
  :ok
end

Limitations vs DoubleDown.ContractFacade

  • No pre_dispatch transforms
  • No @doc tag sync from contract to facade
  • No combined contract + facade in one module
  • Param names are synthesized for bare (unannotated) types
  • No compile-time spec mismatch warnings

See also