# Metaprogramming: how to use variables from enclosing scope?

**URL:** https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520
**Category:** General Usage
**Tags:** question
**Created:** [November 23, 2016, 10:53am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520 "2016-11-23T10:53:37Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![floswald](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/floswald/32/195_2.png) [@floswald](https://discourse.julialang.org/u/floswald)
#### Post date: [November 23, 2016, 10:53am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/1 "2016-11-23T10:53:37Z")

</div>

I want to use `@eval` to generate code that does the same thing for different symbols. I keep going back to this example from [Logging.jl](https://github.com/kmsquire/Logging.jl/blob/master/src/logging_macros.jl), even though it’s not the best example. Here is my contrived use case:

```julia
"""
find all elements of `x` and `y` according to some rule and put them into aptly named dictionaries. return the dictionaries.
"""
function func()
    x = rand(10)
    y = rand(10)

    x_idx = x.< 0.5
    y_idx = y.> 0.5

    for (gg,idx,vals) in ((:xDict,:x_idx,:x),(:yDict,:y_idx,:y))
        @eval begin
            ($gg) = Dict(zip($idx,$vals[$idx]))
        end
    end
    return (xDict,yDict)
end

julia> func()
ERROR: UndefVarError: x_idx not defined
 in eval(::Module, ::Any) at ./boot.jl:234
 in eval(::Module, ::Any) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
 in func() at ./REPL[84]:9

```

How can I use `x_idx` inside this `@eval`?

---

<div class="post-metadata">

### Author: ![slowbrain](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/slowbrain/32/2224_2.png) [@slowbrain](https://discourse.julialang.org/u/slowbrain)
#### Post date: [November 23, 2016, 11:19am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/2 "2016-11-23T11:19:24Z")

</div>

does this make it for you?

```julia
function func()
           x = rand(10)
           y = rand(10)

           x_idx = find(x.< 0.5)
           y_idx = find(y.> 0.5)

           for (gg,idx,vals) in ((:xDict,x_idx,x),(:yDict,y_idx,y))
               @eval begin
                   ($gg) = Dict(zip($idx,$vals[$idx]))
               end
           end
           return (xDict,yDict)
       end

```

---

<div class="post-metadata">

### Author: ![floswald](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/floswald/32/195_2.png) [@floswald](https://discourse.julialang.org/u/floswald)
#### Post date: [November 23, 2016, 11:36am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/3 "2016-11-23T11:36:05Z")

</div>

yes! cool, thanks. bit stupid on my behalf. i think i got it now, actually much simpler than I thought. this is literally just interpolating symbols into expressions…

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [November 23, 2016, 12:52pm UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/4 "2016-11-23T12:52:46Z")

</div>

Note that is “solution” is not interpolating symbols into the expression. Also this is not the proper way to do metaprogramming since almost everything are running in the global scope (`xDict` and `yDict` are global variables). It is impossible to use `eval` to get or set local variables and it is extremely unlikely it will ever be possible.

---

<div class="post-metadata">

### Author: ![floswald](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/floswald/32/195_2.png) [@floswald](https://discourse.julialang.org/u/floswald)
#### Post date: [November 23, 2016, 2:19pm UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/5 "2016-11-23T14:19:42Z")

</div>

I’m not sure I understand. my use case puts that example function inside a module like so:

```julia

julia> module Testm

       function func()
                  x = rand(10)
                  y = rand(10)

                  x_idx = find(x.< 0.5)
                  y_idx = find(y.> 0.5)

                  for (gg,idx,vals) in ((:xDict,x_idx,x),(:yDict,y_idx,y))
                      @eval begin
                          ($gg) = Dict(zip($idx,$vals[$idx]))
                      end
                  end
                  return (xDict,yDict)
              end

       end
Testm

julia> xDict = 0
0

julia> yDict = 0
0

julia> z=Testm.func()
(Dict(7=>0.282879,4=>0.471219,9=>0.10263,10=>0.24691,2=>0.257844,1=>0.378451),Dict(10=>0.76719,5=>0.543434,6=>0.858241))

julia> xDict
0

```

so it doesn’t seem to overwrite the global `xDict`. Would you recommend something different to achieve what I’m after?

---

<div class="post-metadata">

### Author: ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)
#### Post date: [November 23, 2016, 2:24pm UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/6 "2016-11-23T14:24:45Z")

</div>

A eval statement will always evaluate in the global scope of the module it is located in. Each module has its own separate glocal scope. Your second `xDict` sits in the global scope of `Main` whereas the one from the eval is in `Testm`:

```julia
julia> module Testm

              function func()
                         x = rand(10)
                         y = rand(10)

                         x_idx = find(x.< 0.5)
                         y_idx = find(y.> 0.5)

                         for (gg,idx,vals) in ((:xDict,x_idx,x),(:yDict,y_idx,y))
                             @eval begin
                                 ($gg) = Dict(zip($idx,$vals[$idx]))
                             end
                         end
                         return (xDict,yDict)
                     end

              end
Testm

julia> Testm.xDict
ERROR: UndefVarError: xDict not defined

julia> Testm.func() # this creates Testm.xDict
(Dict(7=>0.366333,4=>0.193313,3=>0.341151,5=>0.141716,8=>0.479359),Dict(3=>0.865234,5=>0.722114,8=>0.759312))

julia> Testm.xDict
Dict{Int64,Float64} with 5 entries:
  7 => 0.366333
  4 => 0.193313
  3 => 0.341151
  5 => 0.141716
  8 => 0.479359

```

---

<div class="post-metadata">

### Author: ![floswald](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/floswald/32/195_2.png) [@floswald](https://discourse.julialang.org/u/floswald)
#### Post date: [November 23, 2016, 2:28pm UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/7 "2016-11-23T14:28:55Z")

</div>

ok i see - this may be an undesirable side effect indeed. thanks for pointing this out. any ideas for how to do this diffrently most welcome.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [November 23, 2016, 2:45pm UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/8 "2016-11-23T14:45:16Z")

</div>

Do no use `eval` in functions. The Logging.jl code you referred to does not do that in a function and is meant to define globals.

If you want to save some typing on the `gg =Dict(zip(idx, vals[idx]))` line, you can write a macro, say `@m`, to expand `@m gg idx vals` to that. Sth like

```julia
macro m(gg, idx, vals)
    :($(esc(gg)) = Dict(zip($(esc(idx)), $(esc(:($vals[$idx]))))))
end

```

Should do it.

---

<div class="post-metadata">

### Author: ![akis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/akis/32/156_2.png) [@akis](https://discourse.julialang.org/u/akis)
#### Post date: [November 23, 2016, 8:53pm UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/9 "2016-11-23T20:53:59Z")

</div>

If saving typing is the actual goal, maybe you can take some idea from this:

```julia
xDict, yDict = map(((x_idx, x), (y_idx, y))) do t
                 idx, vals = t
                 Dict(zip(idx, vals[idx]))
               end

```

---

<div class="post-metadata">

### Author: ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)
#### Post date: [November 24, 2016, 4:25am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/10 "2016-11-24T04:25:00Z")

</div>

> [@yuyichao](#):
>
> Do not use eval in functions.

This is an oversimplification. One should not use `eval` unless one intends to have effects at global scope. But if one is building new types and methods specialized on those types, functions may be helpful. Graham (“On Lisp”) says to use functions rather than macros where possible. I suspect that some of the macro code in the spectacular StaticArrays package could be cleaned up or made more flexible by use of functions employing `eval`. Perhaps @andyferris has tried this and found otherwise?

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [November 24, 2016, 5:00am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/11 "2016-11-24T05:00:00Z")

</div>

> [@Ralph\_Smith](#):
>
> This is an oversimplification.

Sure, but not by much. There are few cases that you need to do it but I don’t think any cases mentioned anywhere in this thread so far is one of those.

> [@Ralph\_Smith](#):
>
> intends to have effects at global scope. But if one is building new types and methods specialized on those types, functions may be helpful.

In most of those cases you shouldn’t put the code in a function to start with.

> [@Ralph\_Smith](#):
>
> I suspect that some of the macro code in the spectacular StaticArrays package could be cleaned up or made more flexible by use of functions employing eval.

At a quick glance that’s exactly the opposite. This is also why I don’t want to use the few corner cases to confuse people that don’t need to worry about it. For most people, remember to not use `eval` in a function should be good enough.

---

<div class="post-metadata">

### Author: ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)
#### Post date: [November 24, 2016, 5:54am UTC](https://discourse.julialang.org/t/metaprogramming-how-to-use-variables-from-enclosing-scope/520/12 "2016-11-24T05:54:11Z")

</div>

I’m not certain how to use `eval` nicely in _StaticArrays_. The macros (e.g. `v = @SVector [1,2,3]`) are just there to convert common Julia array creation syntax into the appropriate _StaticArrays_ constructor, because (a) the types have many type parameters and can be pain to write by hand and (b) people are familar with the standard array creation syntax. I could (and should) use functions inside my (disgusting) macros to amalgamate common code. Calling `eval` however would be very slow.

(as an aside, where I would _love_ to use is in a `@generated` function’s generator but that is forbidden because the compiler writers (quite reasonably) don’t want to e.g. guarantee that function generators run exactly once, or deal with complications that mutating the state of the system in the middle of certain compilation steps would involve, which is fair enough! 🙂 )

But yes, in (rare) cases where you are doing a lot of complicated code generation or need to something special in ` __init__ ()` then it might be reasonable to use `eval()` in functions that usually _are called once_ (or a fixed number of times) when the package compiles or is loaded.
