Eval() vs @eval


#1

I expected that the two forms would yield identical results. But to my surprise:

julia> @eval :x
:x

julia> eval(:x)
ERROR: UndefVarError: x not defined
Stacktrace:
 [1] top-level scope
 [2] eval at ./boot.jl:319 [inlined]
 [3] eval(::Symbol) at ./client.jl:389
 [4] top-level scope at none:0

Is that to be expected?


#2

OK, they definitely don’t have the same behaviour:

julia> ex = :(x = 2)
:(x = 2)

julia> eval(ex)
2

julia> x
2

julia> ex = :(y = 2)
:(y = 2)

julia> @eval ex
:(y = 2)

julia> y
ERROR: UndefVarError: y not defined

#3

Useful?


#4

Nevermind, I figured it out… Silly me, the @eval macro should take an expression as an argument, not a Symbol!


#5

Yes. The input to macros is always converted to an expression, the output is getting evaluated. So, when you do @eval :x, inside the macro the argument is :(:x). When that gets returned, it is evaluated, giving the symbol :x.

By contrast, eval takes as an argument an Expr or Symbol object. So, when it runs, it’s running the code contained in that Expr (or Symbol) which is in this case just x.


#6

Thanks – I figured it out that I was @evaling a Symbol into existence.


#7

Yessss, thank you! :slight_smile:


#8

You can splice expressions into @eval, so you can make your examples work:

julia> ex = :(y = 2)
:(y = 2)

julia> @eval $ex
2

julia> y
2