# Evaluating expression on tuple of variables doesn't work inside function

**URL:** https://discourse.julialang.org/t/evaluating-expression-on-tuple-of-variables-doesnt-work-inside-function/92423
**Category:** General Usage
**Tags:** metaprogramming
**Created:** [January 2, 2023, 5:55pm UTC](https://discourse.julialang.org/t/evaluating-expression-on-tuple-of-variables-doesnt-work-inside-function/92423 "2023-01-02T17:55:29Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![derikk](https://avatars.discourse-cdn.com/v4/letter/d/76d3ee/32.png) [@derikk](https://discourse.julialang.org/u/derikk)
#### Post date: [January 2, 2023, 5:55pm UTC](https://discourse.julialang.org/t/evaluating-expression-on-tuple-of-variables-doesnt-work-inside-function/92423/1 "2023-01-02T17:55:29Z")

</div>

I’m trying to write a function that takes in an expression and an assignment to a set of variables, and outputs the expression evaluated on those variables. I came up with the following code:

```julia
function eval_vars(expr::Expr, vars::NamedTuple)
    func = eval(Expr(:->, Expr(:parameters, keys(vars)...), expr))
    return func(; vars...)
end

```

As an example, suppose I define `ex = :(a^2 + b^2)` and `vs = (a=3, b=4)`. Then I want `eval_vars(ex, vs)` to return `25`.

What’s really odd is when I run these lines one by one I get exactly what I’m expecting:

```julia
julia> ex = :(a^2 + b^2)
:(a ^ 2 + b ^ 2)

julia> vs = (a=3, b=4)
(a = 3, b = 4)

julia> func = eval(Expr(:->, Expr(:parameters, keys(vs)...), ex))
#50 (generic function with 1 method)

julia> func(; vs...)
25

```

But when I call `eval_vars`, I get an error:

```julia
julia> eval_vars(ex, vs)
ERROR: MethodError: no method matching (::var"#53#55")(; a=3, b=4)
Closest candidates are:
  (::var"#53#55")(; a, b) at none:0
Stacktrace:
 [1] eval_vars(expr::Expr, vars::NamedTuple{(:a, :b), Tuple{Int64, Int64}})
   @ Main ./REPL[46]:3
 [2] top-level scope
   @ REPL[47]:1

```

Why is this a `MethodError` if the candidate mentioned is an exact match? Why does this code work on its own but not when inside of a function?

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [January 2, 2023, 7:24pm UTC](https://discourse.julialang.org/t/evaluating-expression-on-tuple-of-variables-doesnt-work-inside-function/92423/2 "2023-01-02T19:24:14Z")

</div>

Eval works in the global scope and can be tricky to use within functions. Changing your definition such that it creates a function with positional arguments gives a hint

```julia
julia> function eval_vars(expr::Expr, vars::NamedTuple)
           foo = eval(Expr(:->, Expr(:tuple, keys(vars)...), expr))
           @show methods(foo)
           return foo(values(vars)...)
       end
eval_vars (generic function with 1 method)

julia> eval_vars(ex, vs)
methods(foo) = # 1 method for anonymous function "#62":
[1] (::var"#62#63")(a, b) in Main
ERROR: MethodError: no method matching (::var"#62#63")(::Int64, ::Int64)
The applicable method may be too new: running in world age 32477, while current world is 32478.
Closest candidates are:
  (::var"#62#63")(::Any, ::Any) at none:0 (method too new to be called from this world context.)

```

I.e., the created function cannot be called immediately, but only after your function returns:

```julia
julia> function eval_vars(expr::Expr, vars::NamedTuple)
           return eval(Expr(:->, Expr(:parameters, keys(vars)...), expr))
       end
eval_vars (generic function with 1 method)

julia> eval_vars(ex, vs)(; vs...)
25

```

The simplest way to evaluate everything within a function, is to create an expression which directly computes the desired result when evaluated, e.g.,

```julia
julia> function eval_vars(expr::Expr, vars::NamedTuple)
           eval(:(let $(map((k, v) -> :($k = $v), keys(vars), values(vars))...); $expr end))
       end
eval_vars (generic function with 1 method)

julia> eval_vars(ex, vs)
25

```

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [January 2, 2023, 7:44pm UTC](https://discourse.julialang.org/t/evaluating-expression-on-tuple-of-variables-doesnt-work-inside-function/92423/3 "2023-01-02T19:44:04Z")

</div>

> [@derikk](#):
>
> Why does this code work on its own but not when inside of a function?

The function you try to run didn’t exist when you called `eval_vars`. `invokelatest` can work around this problem.

```julia
julia> function eval_vars(expr::Expr, vars::NamedTuple)
           func = eval(Expr(:->, Expr(:parameters, keys(vars)...), expr))
           return Base.invokelatest(func; vars...)
       end
eval_vars (generic function with 1 method)

julia> eval_vars(:(a^2 + b^2), (a=3, b=4))
25

```
