I’m learning the basics of macros. Coming from another LISP-inspired language (Wolfram Mathematica), I’m wondering why there is a distinction between macros and functions. Isn’t a macro just a function whose argument is an expression? Is it correct to say that the “macro” keyword is just syntax sugar which allows you to write
@some_marco expression
instead of
some_function(:(expression)) ?
Welcome to Julia-discourse!
No, the difference is when the function/macro is evaluated. The latter is done at parse-time, i.e. before the code is run. Watch Jacob Quinn: What happens when - From parse time to compile time - YouTube
You can actually call it as a function. Try var"@some_macro"(LineNumberNode(@__LINE__, @__FILE__), @__MODULE__, :(expression))
instead, e.g.
julia> var"@show"(LineNumberNode(@__LINE__, @__FILE__), @__MODULE__, :(1 + 2))
quote
println("1 + 2 = ", repr(begin
#= show.jl:641 =#
value = $(Expr(:escape, :(1 + 2)))
end))
value
end
The var"..."
around the macro name is just so that the @
in front of the name gets interpreted as just a name, not as an actual macro call. The LineNumberNode
and module tell the macro where it is expanded in, which can be useful for debugging and a lot of other things.
Thanks for the explanation. If you don’t care about performance penalties, is it OK to use a function to manipulate the syntax tree of an expression and then hit the modified expression with “eval”? For example, here’s a function which changes any integer assignment like “a=100” into a float assignment like “a=100.0”.
function change(expr::Expr)
if expr.head == :(=)
expr.args[2] = float(expr.args[2])
eval(expr)
return 0
else
return -1
end
end
Then I can call the function with
change(:(a=100))
In the end, the value of “a” will be the floating-point number 100.0.
No it’s not. They have completely different scope. There’s no way to emulate macros with eval
. eval
only runs in global scope and have no access to any local variables that’s accessible by code returned from macros.