Constructing qualified function calls in a macro

I’m writing module that will accept a function name and arguments looking like foo(bar, baz) - as Kernel.def/2 does but without a body, and given M is known at compile time I want it to expand to:

def foo(bar, baz), do: M.foo(bar, baz)

I can see how to do this by manipulating the AST. The :foo in:
{:foo, [], [{:bar, [], Elixir}, {:baz, [], Elixir}]} # => foo(bar, baz)
…becomes…
{:., [], [{:__aliases__, [alias: false], [:M]}, :foo]}

In Lisp you’d be able to do something like this using the quote/unquote forms - is it possible in Elixir?

PS. I don’t think defdelegate is right for this as the function body generated by the macro may be more complicated - this is just the part I couldn’t see a nice approach for.

Yes, very similar to lisp.

defmacro mydef(fun, args) do
  quote do
    def unquote(fun)(unquote(args)) do
      MyModule.unquote(fun)(unquote(args))
    end
  end
end

This is an overly simplistic implementation but it might be enough for your needs.

Take a look at the implementation of the defdelegate macro and you’ll see it’s basically doing the same thing as the code above - only more generalised.

4 Likes