🎓 A1Learner
🔍
0 of 47 lessons completed

Julia Macro Systems

A macro system is a macro that takes a whole block, uses safe introduced names, and expands into several statements. Safe introduced names never clash with caller names.

One macro call can run a statement twice

The macro expands into the escaped statement two times in order.

macro twice(stmt)
    return quote
        $(esc(stmt))
        $(esc(stmt))
    end
end
count = 0
@twice count += 1
println(count)

A fresh name leaves the caller variable alone

The macro stores 5 in a fresh name, adds 100, and the caller variable named tmp stays 7.

macro add_temp(val)
    t = gensym()
    return quote
        $t = $(esc(val))
        $t + 100
    end
end
tmp = 7
println(@add_temp 5)
println(tmp)

A macro can take a whole block

The macro expands into the escaped block two times in order.

macro run_twice(block)
    return quote
        $(esc(block))
        $(esc(block))
    end
end
count = 0
@run_twice begin
    count += 1
end
println(count)

Example

macro swap(a, b)
    t = gensym()
    return quote
        $t = $(esc(a))
        $(esc(a)) = $(esc(b))
        $(esc(b)) = $t
    end
end
x = 1
y = 2
@swap x y
println(x)
println(y)

Key points

  • Whole block: A macro can take a whole block as its input, not just one value.
  • Escaped names: esc marks a name as belonging to the caller, so it keeps its caller meaning.
  • Fresh name: gensym makes a name no caller code can clash with.
  • Several statements: One macro call can expand into several statements in order.
  • Use a fresh name for a temporary value a macro introduces, and escape caller names.

In this example, the macro stores x in a fresh name, copies y into x, copies the fresh name into y, and the printed values show the swap.

Note

A temporary name made with gensym stays separate from a caller variable with a plain name.

Try it Yourself

Edit the code, then press Run.

Running is simulated · JuliaHub

Exercise

Why does a macro use a fresh name for a temporary value?