Eval_quoted in the current scope

This is a bit of an odd question but I am curious. I can start up a new iex session, assign a variable, and look at the bindings in the current scope:

iex(1)> x = 1
iex(2)> binding()
[x: 1]

Which is neat. Now I can create a quoted expression that assigns a value to a different variable:

iex(3)> expr = quote do var!(y) = 2 end 
{:=, [], [{:var!, [context: Elixir, import: Kernel], [{:y, [], Elixir}]}, 2]}

and I can see what the result of evaluating that expression against the current binding might be:

iex(4)> Code.eval_quoted(expr, binding())
 [expr: {:=, [],
   [{:var!, [context: Elixir, import: Kernel], [{:y, [], Elixir}]}, 2]}, x: 1,
  y: 2]}

So we see that if I evaluated the expression starting with a set of bindings just like the bindings in my current context, that the result would have a value of 2 and the new set of bindings would include the variable y with a value of 2.

However if I actually check my bindings after the eval call, I see:

iex(5)> binding()
[expr: {:=, [],
  [{:var!, [context: Elixir, import: Kernel], [{:y, [], Elixir}]}, 2]}, x: 1]

So evaluating the quoted expression didn’t actually change the current bindings (just showed me what could have happened). This makes total sense since I created a copy of my current bindings (an immutable object) and passed it along.

Is there any way to evaluate the quoted expression (i.e. expr) in the current context so that it actually changes the current set of bindings?

I am pretty sure a macro is the only way to let a quoted expression modify the current context.

1 Like

I think this too. eval'ing the AST allows runtime execution, but to alter the context requires built-time execution.

Yeah. I looked at the iex source and I see where the current set of bindings is maintained. It’s been kind of a cool learning experience. Thank you both for your help.