Macro only works outside of a function

I have this example code and I do not get why it does not work in function test

macro dump(arg)
    return :(println("dump", $arg))
end

a = 1
@dump a

function test()
    b = 2
    @dump b
end

test()

This is macro hygiene at work. Macros need to be careful about what the names they use actually reference. For example, within function test, you could also have a variable named println = 3. If the macro tried to literally splice in the expression println("dump", b), then it’d try to use 3 as the function and try to call it. So instead it uses “hygiene” to ensure that the println the macro inserted actually referenced the thing the macro wanted it to.

The way macros opt-out of this hygeine is with the esc function. In this case, you want the arg to be evaluated in the namespace of the caller, so you remove the hygiene for it:

macro dump(arg)
    return :(println("dump", $(esc(arg))))
end

This will now work as you expected within functions and in other modules. Hopefully you can also now see why your initial version worked at global scope — both the macro and the caller are in the same namespace!

3 Likes

Thank you very much!