Having a problem with macros


#1

All,

I appear not to be understanding macros.

Question: Why is my variable not being resolved when it’s called from within a macro?

Thanks in advance

Here is my macro:

macro SW1(criteria) 
    return println(""" "$criteria," """)
end

If I simply run the return statement, I get the desired result, which is a quoted string with comma. See below:

julia> x = "ABC"
"ABC"

julia> println(""" "$x," """)
 "ABC,"

But if I use my macro, I get this:
julia> @SW1 x
“x,”

Question: Why is my variable not being resolved?


#2

Macros transform syntax to syntax. Normally you return syntax in the form of a quoted expression from a macro, but if you leave out the quotes, what you return is just treated as a constant. Inside the macro body, criteria is :x, i.e. a symbol named x (the syntax that constitutes the macro’s input); the macro body never sees the value bound to x. Once you understand that, it follows that e.g. "$(:x)" is just the string "x" (which you can test at the REPL as well), and that’s why you get this result.

What you want instead is to have the macro create code (in the form of a quoted expression) that references x. This is made a little bit more confusing in this case by the fact that $ is used both to interpolate into quoted expressions, as well as to interpolate into strings. To avoid this confusion, I’d propose doing the string interpolation in a separate function, called in the code generated by the macro. Furthermore, you’ll should escape the input using esc:

criteria_string(criteria) = """ "$criteria," """ # *string* interpolation

macro SW2(criteria)
    return quote
        println(criteria_string($(esc(criteria)))) # *expression*  interpolation
    end
end

If you’re wondering what happens when you don’t use esc, here’s an example:

module M

export @SW2

x = 1

criteria_string(criteria) = """ "$criteria," """

macro SW2(criteria)
    return quote
        println(criteria_string($criteria))
    end
end

end

using Main.M
x = 2
@SW2(x)

Which prints "1,"! This is because without esc, x will be resolved in the macro definition environment (i.e. module M), while you want it to refer to the x that’s in the macro call environment (the one outside M).