Meta.parse + eval does not work as expected in the loop

I would expect the first for loop below to work, but apparently for some reason loop index (n) is not recognized in eval(xpr). I am guessing it has something to do with scoping etc.
Is there a way to make it work “as expected” in this case i.e. to nudge eval(Meta.parse()) to recognize loop index?

xpr = Meta.parse("3^n")
for n in 1:3 # ERROR: UndefVarError: n not defined
   println("n= ", n, ", xpr= ", xpr, ", eval(xpr)= ", eval(xpr))
end
for nn in 1:3 # this works as expected
   global n = nn
   println("n= ", n, ", 3^n= ", eval(Meta.parse("3^n")))
end

eval always always happens in the global scope, don’t do eval in loop

3 Likes

I do not really understand potential ramifications of allowing eval() work in local scope as well, I guess, but it would be very handy. For now, with the silly global n = nn above I can do what I need to do.

eval working in the local scope is exactly why languages like python and R are impossible to optimize. In general, the fact that you are trying to do this implies you are doing something wrong.

5 Likes

I would appreciate some suggestion what can I do to avoid using eval() in this case.
Basically, I want the user of the function (invoked from the command line script) to be able to pass simple (but arbitrary) function (ufun) to evaluate some value dependent on the loop index. For example:

function foo(maxit, ufun)
  for n in 1:maxit
      v = ufun(n)
      [...]
  end
end

where ufun(n) can be e.g. 2^n, n^2, 6*n, etc.

parse the code, then construct a function at the global scope level, then in your code call that function.

expr = Meta.parse("x^2")
fdefexpr = :(x -> $(expr))
f = eval(fdefexpr)
f(2)

Be very careful about the fact that you are evaluating potentially arbitrary code provided by the user…

2 Likes

Thanks a ton! It is very helpful. […]

Be very careful about the fact that you are evaluating potentially arbitrary code provided by the user…

I am the only user so far… but definitely very good point!