Don’t use eval within a macro. A macro is a function that get’s a parsed, yet unevaluated, expression as input and can transform it into another expression which is to be executed instead.
More concretely, let’s write @moo with a single variable as input:
What input does @moo get when called as @moo a?
julia> expr = Meta.parse("a") # argument expression after being parsed
:a
julia> typeof(expr)
Symbol
julia> dump(expr) # expression, i.e., input to @moo will just be a symbol
Symbol a
From this symbol, we now want to construct a more complicated expression which contains the literal symbol as well as its name as a string
julia> res_expr = Meta.parse("a = foo(\"a\")")
:(a = foo("a")) # desired output of @moo a
julia> dump(res_expr)
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol a
2: Expr
head: Symbol call
args: Array{Any}((2,))
1: Symbol foo
2: String "a"
Now, the macro is a pure function which takes the symbol as input and produces the desired expression as output:
julia> macro moo(var)
# Return expression with symbol interpolated literally on the lhs and as a string on the rhs
:($(esc(var)) = foo($(string(var))))
end
@moo (macro with 1 method)
julia> @macroexpand @moo a # Macro indeed transforms the given symbol into the desired expression
:(a = Main.foo("a"))
Be sure to also read the Metaprogramming chapter from the Julia manual. Other good sources to understand macros in general, i.e., not just in Julia, are On Lisp or Practical Common Lisp.
The basic idea is that if you write something like
macro foo(ex)
quote
x = 1
y = x + $ex
end
end
it would be very bad and surprising if the variables referred to there affected code outside of the macro unless you specifically intend it to. E.g. consider this:
function f(x)
@foo x
x
end
Without macro hygiene, f(2) would return 1, which might be very surprising. So instead what happens is this:
julia> @macroexpand @foo ex
quote
#= REPL[17]:3 =#
var"#59#x" = 1
#= REPL[17]:4 =#
var"#60#y" = var"#59#x" + Main.ex
end
So the intermediate variables here aren’t actually named x or y, they get names that are guaranteed to not clash with surrounding code.
However, sometimes you don’t want this, especialy if you need to actually return and evaluate code that a user passed into the macro. So when you write esc(expr), that essentially is a marker saying "I want everything inside expr to not be made hygenic.