How to use defdelegate

We use defdelegate when we want a function in module A to have the same behavior of other function in module B. (Is the equivalent of calling function B directly but from another module) This decoupling of functions can help us to create a public API, for the users of module A just have to call the functions inside module A, and the implementation details can be done under the hood in module B.

defmodule Calculator do

  alias Cache.Fibonacci

  defdelegate start, to: Fibonacci
  defdelegate calculate_fib(n), to: Fibonacci, as: :get_fib

  end
end

In the first defdelegate we delegate the function Calculator.start to a function (with the same name) in the module Cache.Fibonacci. (Remember alias turns “Cache.Fibonacci” into “Fibonacci”)

If you saw that first example only you would think that we don’t have to worry about arguments, but that’s not true, only if the functions have zero arguments you can skip the function(args) notation.

The second defdelegate, delegates calculate_fib(n) to the function get_fib inside the Cache.Fibonacci module

Now, you can’t do pattern matching in defdelegate you can only pass arguments, so if you have some sort of pattern matching you have to pass several arguments like this:

defmodule Calculator do

  alias Cache.Fibonacci

  defdelegate start, to: Fibonacci
  defdelegate calculate_fib(n), to: Fibonacci, as: :get_fib
  defdelegate calculate_fib(n, dict), to: Fibonacci, as: :get_fib

end

 

This is the Cache.Fibonacci module, you can see how that the “dict” parameter is eventually pattern matched to %{key: “value”}

defmodule Cache.Fibonacci do

@me __MODULE__

#Public API
def start() do
    Agent.start_link(fn -> %{0 => 0, 1 => 1} end, name: @me)
end

def get_fib(n) do
fib(n, in_map?(n))
end

def get_fib(n, %{key: "value"}) do
n
end

...

end

Leave a Reply

Your email address will not be published. Required fields are marked *