Elixir Advanced Macros
An advanced macro is a macro that builds new code from values given at the call site. It can define functions, repeat an expression, or choose code by matching a literal value.
A macro can repeat an expression
The macro inserts the call twice. The caller prints 42.
defmodule Twice do
defmacro double(call) do
quote do
unquote(call) + unquote(call)
end
end
end
defmodule Caller do
require Twice
def value, do: Twice.double(21)
end
IO.puts(Caller.value())A macro can define functions
The macro turns each name and value into a function. The caller prints both results.
defmodule Maker do
defmacro make(name, value) do
quote do
def unquote(name)(), do: unquote(value)
end
end
end
defmodule Caller do
require Maker
Maker.make(:answer, 42)
Maker.make(:greeting, "hi")
end
IO.puts(Caller.answer())
IO.puts(Caller.greeting())A macro can choose code by literal value
Two macro clauses match two literal values. The caller prints one line for each.
defmodule Status do
defmacro describe(:ok) do
quote do: "all good"
end
defmacro describe(:error) do
quote do: "failed"
end
end
defmodule Caller do
require Status
def first, do: Status.describe(:ok)
def second, do: Status.describe(:error)
end
IO.puts(Caller.first())
IO.puts(Caller.second())Example
defmodule Maker do
defmacro make(name, value) do
quote do
def unquote(name)(), do: unquote(value)
end
end
end
defmodule Twice do
defmacro double(call) do
quote do
unquote(call) + unquote(call)
end
end
end
defmodule Caller do
require Maker
require Twice
Maker.make(:base, 40)
def doubled, do: Twice.double(21)
def total, do: base() + doubled()
end
IO.puts(Caller.base())
IO.puts(Caller.doubled())
IO.puts(Caller.total())Key points
- Macro: a macro is code that writes code during compilation.
- Call site: the call site is the place where a macro is used.
- Expansion: expansion is the code a macro produces for a call.
- Require: a caller module must require a macro module before it uses its macros.
- Separate module: a macro call lives in a caller module that is separate from the module that defines the macro.
In this example, the maker macro defines a base function, the double macro expands to 21 + 21, and the total function adds the two results.
Note
a macro argument that is a literal value can be matched in the macro definition, as in the status example.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does Twice.double(21) expand to?