Eduardo
Eduardo

Reputation: 590

How to define a function based on a previously defined function on a module?

I'm trying to define a function based on a already defined function on a module.

I want to do something like this:

defmodule A do
  def my_func(pid, arg1, arg2) do
    send pid, "Do Something"
  end
end

And after my_func is defined, I would like to define my_func(arg1, arg2) that calls my_func passing a pid that I'll get from a pool of pids for example.

My first attempt was using @on_definition but I had no success. Then I tried doing this inside the module:

Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
  args = Enum.map(0..arity-1, fn i -> "arg_#{i}" end)
      quoted = quote do
  def unquote(func_name)(unquote_splicing(args)) do
     ....

But still I'm not having success. Anyone have any idea on how do I get this? :)

Upvotes: 1

Views: 209

Answers (2)

sasajuric
sasajuric

Reputation: 6059

Actually, the solution by bitwalker can be simplified. You don't need to quote and do eval_quoted, since def is a macro that injects directly into AST. So this will work as well:

defmodule Test do
  def my_func(pid, arg1, arg2) do
    send pid, {arg1, arg2}
  end

  Enum.map Module.definitions_in(__MODULE__, :def), fn {func_name, _arity} ->
    def unquote(func_name)(arg1, arg2) do
      pid = :some_pid
      unquote(func_name)(pid, arg1, arg2)
    end
  end

  Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
    IO.inspect {func_name, arity}
  end
end

Upvotes: 3

bitwalker
bitwalker

Reputation: 9261

You can accomplish this like so:

defmodule Test do
  def my_func(pid, arg1, arg2) do
    send pid, {arg1, arg2}
  end

  quoted = Enum.map Module.definitions_in(__MODULE__, :def), fn {func_name, _arity} ->
    quote do
      def unquote(func_name)(arg1, arg2) do
        pid = :some_pid
        unquote(func_name)(pid, arg1, arg2)
      end
    end
  end
  Module.eval_quoted(__MODULE__, quoted)

  Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
    IO.inspect {func_name, arity}
  end
end

If you compile this with elixirc test.ex, you'll see it spit out the definitions for my_func/2 and my_func/3. The problem with your initial code was that while you were mapping over and quoting the definitions, you never evaluated those quoted expressions, so they were not compiled as part of your module.

Upvotes: 3

Related Questions