# Macros and Metaprogramming — Elixir & Phoenix

Source: https://www.geekswithgeeks.com/en/elixir-phoenix/a-macros

> Understand quote, unquote, use and when to write macros.

## Code that writes code

Elixir code is represented internally as an **AST** of three-element tuples, and **macros** transform that AST at compile time. **`quote`** turns code into its AST, and **`unquote`** injects values into a quoted expression. **`defmacro`** defines a macro whose arguments arrive as AST and whose return value is AST inserted at the call site. Much of Elixir itself is built with macros: `if`, `unless`, `defstruct`, `|>` and the `test "..." do` syntax in ExUnit are macros. **`use Module`** calls that module's `__using__/1` macro, which typically injects functions, imports and module attributes; this is how `use GenServer`, `use Phoenix.Controller` and `use Ecto.Schema` work. Macros are **hygienic**: variables defined inside a macro do not leak into the caller unless you use `var!`. Use `Macro.to_string` and `Macro.expand` to inspect them. The community guideline is clear: **do not write a macro when a function will do**. Macros make code harder to read and debug, so reserve them for DSLs, compile-time validation and removing real boilerplate.

## A small macro and a __using__ hook

quote and unquote generate functions at compile time.

```elixir
defmodule Shop.Statuses do
  @doc "Generates predicate functions such as paid?/1 for each status."
  defmacro defstatuses(statuses) do
    defs =
      for status <- statuses do
        name = :"#{status}?"

        quote do
          def unquote(name)(%{status: s}), do: s == unquote(status)
        end
      end

    quote do
      unquote_splicing(defs)
    end
  end
end

defmodule Shop.OrderStatus do
  require Shop.Statuses
  Shop.Statuses.defstatuses([:placed, :paid, :shipped])
end

IO.inspect(Shop.OrderStatus.paid?(%{status: :paid}))      # true

defmodule Shop.Auditable do
  defmacro __using__(opts) do
    entity = Keyword.fetch!(opts, :entity)

    quote do
      require Logger

      def audit(action, id) do
        Logger.info("#{unquote(entity)} #{id}: #{action}")
      end
    end
  end
end

defmodule Shop.Invoices do
  use Shop.Auditable, entity: "invoice"           # injects audit/2
end

IO.inspect(quote(do: 1 + 2))                        # {:+, [context: Elixir, imports: ...], [1, 2]}
```

## Functions first

Before writing a macro, try a plain function, a higher-order function or a module attribute. Macros pay off when they remove significant boilerplate or provide compile-time checks that functions cannot.

**Quiz:** What does `use Shop.Auditable, entity: "invoice"` do?

- [ ] Imports a module at run time
- [ ] Creates a process
- [x] Calls Shop.Auditable.__using__/1 at compile time, which injects code into the calling module
- [ ] Installs a dependency

*Answer:* Calls Shop.Auditable.__using__/1 at compile time, which injects code into the calling module. use invokes the __using__ macro, which returns code to inject.
