What are macros in Elixir?

Whenever a compiler encounters a piece of code, it’s converted into an abstract syntax tree (AST).

But how can we make changes to the AST that is formed? The answer is through metaprogramming!

In Elixir metaprogramming, a macro is a special function that returns different ASTs based on the arguments (including ASTs) passed to it.

Modifying the AST using macros

One good example of a macro is redefining the already built unless macro using the if construct in Elixir.

defmacro unless(expression, do: block) do
quote do
if !unquote(expression), do: unquote(block)
end
end

We use the defmacro keyword to create an unless macro that takes an expression and a block. Based on the expression, it executes the block.

The created macro performs the exact same behavior as the already given unless macro in Elixir, but in different way.

defmodule Example do
defmacro unless(expression, do: block) do
quote do
if !unquote(expression), do: unquote(block)
end
end
end
defmodule Test do
require Example
def test_unless do
x = 10
Example.unless(x == 5, do: IO.puts("x is not 5"))
end
end
Test.test_unless()

Macro expansion

Whenever the code is parsed and converted into an AST, the compiler does another run-through to expand any encountered macros. It recursively expands the code until it no longer contains any macro calls.

This expansion recursively executes until all macros have been fully expanded into their final generated code.

Copyright ©2024 Educative, Inc. All rights reserved