3

I have just started using Julia. I am trying to use eval (in Julia) in order to define a set of variables in a function. Let's say I want to set v1 equal to 2:

function fun_test(varargs...)
  v1 = 0;

  if length(varargs) > 0
    j = collect(linspace(1,length(varargs)-1,length(varargs)/2));

    for i in j
      expr_vargs = parse("$(varargs[i]) = $(varargs[i+1]);");
      eval(expr_vargs);
    end
  end

  println(v1)

end

Calling the function as:

fun_test("v1", "2");

It doesn't work, since println returns 0 (the initial value of v1). However, if I run an analogous eval call in the Julia's terminal, then it works.

Could you please clarify why it doesn't work and how to fix it?

merch
  • 945
  • 8
  • 19
  • 1
    your `expr_vargs` is fine. It's the `eval`... – Memming Sep 03 '16 at 13:27
  • Hi @Memming. Could you please clarify what you mean? – merch Sep 03 '16 at 13:46
  • 1
    `eval` works in the global scope, but `v1` is local because of the line `v1=0`. – Chris Rackauckas Sep 03 '16 at 15:09
  • Thanks, is there any alternative in Julia to run a string as an expression in local scope? I have just seen that you might eval an entire function to do what I wish, but I would prefer to avoid it. – merch Sep 03 '16 at 15:11
  • 1
    As @ChrisRackauckas notes, `eval` works in the global scope. Other relevant StackOverflow questions (using google): http://stackoverflow.com/questions/21267962/how-can-i-eval-a-local-variable-in-julia http://stackoverflow.com/questions/28882241/eval-in-function-scope-accessing-function-args http://stackoverflow.com/questions/20174352/julia-speeding-up-eval – Dan Getz Sep 03 '16 at 15:11

1 Answers1

5

eval runs in toplevel scope, not in function scope. It is not possible to dynamically update bindings in function scope. Without knowing your precise use case, I suspect there is a way to do things without dynamic rebinding. In particular, v1, v2, etc. is probably best made into an array, V.

Nevertheless, if you really must, you can always define v1 as a global variable in a submodule:

module FunTest
v1 = 0
function fun_test(varargs...)

  if length(varargs) > 0
    j = collect(linspace(1,length(varargs)-1,length(varargs)/2));

    for i in j
      @eval $(varargs[i]) = $(varargs[i+1])
    end
  end

  println(v1)

end
export fun_test
end
using .FunTest
fun_test(:v1, 2)  # result: 2

(I have also modified your code to avoid parseing strings, which is best done through expression interpolation.)

Fengyang Wang
  • 11,901
  • 2
  • 38
  • 67