Dx.Defd_ behaviour (dx v0.3.5)

View Source

Used to make existing libraries compatible with Dx.Defd.

Defining functions

Define functions using defd_/2. The _ stands for basic or native. defd_ functions are not recompiled by the Dx compiler. They have to return either {:ok, result} or {:not_loaded, data_reqs}. See Dx.Defd.Result for more information and Enum-like functions to work with results.

The input arguments can be a Dx.Scope struct or a Dx.Defd.Fn struct. If you don't want to handle these internal structs, you can tell the compiler to load/unwrap them by providing function information (see next section).

Function information

defmodule MyExt do
  use Dx.Defd_

  @dx_ args: [:preload_scope, :fn], warn_not_ok: "Be careful!"
  defd_ map(enum, mapper) do
    # ...
  end
end

Options

  • args - list or map of argument indexes mapping to argument information
    • List format: [:preload_scope, %{}, :fn] - each element maps to an argument position
    • Map format with special keys (highest to lowest precedence):
      • Positive argument indexes (0..arity-1) counting from the first argument: %{0 => :preload_scope}
      • Negative argument indexes (-1..-arity) counting from the last argument: %{-1 => :preload_scope}
      • :all - sets defaults for all arguments (explicitly defined or not)

Argument information options:

  • :atom_to_scope - whether to wrap atoms in Dx.Scope.all/1
  • :preload_scope - tells the compiler to load any scopes passed via this argument
  • :fn - tells the compiler to unwrap any Dx-specific function definitions
  • {:fn, arity: 2, warn_not_ok: "Can't load data here"} - pass more information about the function
  • :final_args_fn - like fn but assumes that no scopes can be passed to the function in this argument
  • {:final_args_fn, arity: 2, warn_always: "Don't use this function"} - pass more information about the function
  • %{} or [] - placeholder for an argument without any special information

Additional options:

  • warn_not_ok - compiler warning to display when the function possibly loads data
  • warn_always - compiler warning to display when the function is used

Examples

defmodule MyExt do
  use Dx.Defd_

  # Using list format - positional arguments
  @dx_ args: [:preload_scope, %{}, :final_args_fn]
  defd_ my_function(scope, value, callback) do
    # ...
  end

  # Using map format with positive and negative indexes
  @dx_ args: %{0 => :preload_scope, -1 => :fn}, warn_not_ok: "Be careful!"
  defd_ another_function(scope, value, callback) do
    # ...
  end

  # Using :all to set defaults for all arguments
  @dx_ args: %{all: :atom_to_scope, 0 => :preload_scope}
  defd_ process_all(first, second, third) do
    # first will be :preload_scope, all will have :atom_to_scope
  end
end

Compiler annotations & callbacks

There are three ways to provide function information for the Dx compiler:

  1. Using @dx_ module attributes before function definitions:
defmodule MyExt do
  use Dx.Defd_

  @dx_ args: [:preload_scope, %{}, :final_args_fn]
  defd_ my_function(scope, value, callback) do
    # ...
  end

  @dx_ args: %{0 => :preload_scope}, warn_not_ok: "Be careful!"
  defd_ another_function(scope, value) do
    # ...
  end
end

args options will also be derived for functions with omitted default arguments.

  1. Using the @moduledx_ module attribute for module-wide defaults (can only be set once per module):
defmodule MyExt do
  use Dx.Defd_

  @moduledx_ args: %{all: :atom_to_scope},
             warn_always: "This module is deprecated"
end
  1. Implementing the __dx_fun_info/2 callback:
defmodule MyExt do
  use Dx.Defd_

  @impl true
  def __dx_fun_info(fun_name, arity) do
    %FunInfo{args: [:preload_scope, %{}, :final_args_fn]}
  end
end

All three approaches can be combined. The precedence order (highest to lowest) is:

  1. @dx_ function-specific annotations
  • merged into @moduledx_ defaults for that function
  1. __dx_fun_info/2 callback implementations
  • always overrides @moduledx_ defaults
  1. @moduledx_ module-wide defaults
defmodule MyExt do
  use Dx.Defd_

  # Module-wide defaults (lowest precedence)
  # Must be set once with all defaults
  @moduledx_ args: %{all: :preload_scope},
             warn_always: "Module under development"

  # Function pattern in __dx_fun_info (middle precedence)
  def __dx_fun_info(:special_case, 2) do
    %FunInfo{args: [:preload_scope, :final_args_fn]}
  end

  # Function-specific override (highest precedence)
  @dx_ args: [:preload_scope, :fn]
  defd_ process_data(scope, callback) do
    # This function's settings override both __dx_fun_info and @moduledx_
  end

  # Uses __dx_fun_info(:special_case, 2) settings
  defd_ special_case(a, b) do
    # ...
  end

  # Falls back to default @moduledx_ settings
  defd_ other_function(x) do
    # ...
  end
end

Summary

Callbacks

This callback is used to provide information about a function to Dx.Defd.

Callbacks

__dx_fun_info(atom, non_neg_integer)

(optional)
@callback __dx_fun_info(atom(), non_neg_integer()) :: Dx.Defd_.FunInfo.input()

This callback is used to provide information about a function to Dx.Defd.

Functions

defd_(call)

(macro)

defd_(call, list)

(macro)

defscope(call)

(macro)

defscope(call, list)

(macro)