# Struggling to understand this Symbol behaviour - Scope determines error presence?

**URL:** <https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891>\
**Category:** General Usage\
**Tags:** metaprogramming\
**Created:** [June 23, 2018, 1:31am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891 "2018-06-23T01:31:09Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 23, 2018, 1:31am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/1 "2018-06-23T01:31:09Z")

</div>

Hi Julians,

The question relates to **Symbols and metaprogramming** , been through the docs many times but still getting my head around it.

I’ve been struggling to pinpoint a bug in my code for the last 2 days and at last I’ve reduced it to this **minimal example** , can anyone help me understand what’s going on please? (In case it matters, Julia v0.6.3 on Windows 7.)

This code runs fine:

```julia
foo = :foo
@eval ($println)($foo)
> foo

```

and this too:

```julia
foo = :foo

function maintest()
    @eval ($println)($foo)
end

maintest()
> foo

```

**But when I define foo _in the function:_**

```julia
function maintest()
    foo = :foo
    @eval ($println)($foo)
end

maintest()

```

I get:

```julia
ERROR: LoadError: UndefVarError: foo not defined

```

As a sanity check I did the following, which works as expected:

```julia
function maintest()
    foo = "bar"
    @eval ($println)($foo)
end

maintest()
> bar

```

So my question is, _ **why do I get the error when defining the symbol in the function’s hard local scope?** _

Thanks

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 23, 2018, 3:28am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/2 "2018-06-23T03:28:30Z")

</div>

Eval always happens in the global scope. This makes sense because functions are essentially statically compiled so they don’t really have dynamic behavior (giving the speed). If course, if you want to do metaprogramming inside of a function, just metaprogram the AST (and return expressions) or use an `@generated` function to build function expressions. Or, just pull in the global with `global x` in the function if that’s what you want to do.

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [June 23, 2018, 4:47am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/3 "2018-06-23T04:47:16Z")

</div>

The difference between `Symbol` and `String` in `maintest` occurs because: here

```nohighlight
function maintest()
    foo = :foo
    @eval ($println)($foo)
end

```

the value of `$foo` that gets interpolated is `:foo`, so `@eval` is calling `println(foo)` (since `:(println($(:foo)))`), but then `foo` does not exist in that context. The `foo` that is now being called for is a different `foo` (note that the other one is already interpolated).

While here,

```nohighlight
function maintest()
    foo = "bar"
    @eval ($println)($foo)
end

```

the value of `$foo` that is interpolated is `"bar"`, so the commaned given to `@eval` is `println("bar")`, which does not require the lookup of an undefined variable, so that is okay and does not give an error.

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 23, 2018, 10:09pm UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/4 "2018-06-23T22:09:14Z")

</div>

Thanks for your explanation that makes sense. I’ve gone over the @generated and AST docs several times to try and understand your suggestions, I was wondering if you might be able to give a small code example to demonstrate? Essentially, in (Julia-esque) pseudocode, what I’m trying to achieve is this:

```julia

function (self::ImmutableStruct, fieldsToModify::Array{Symbol,1})
    for i in fieldsToModify
        i = modifyingFunction( getfield(self, i) )
    end
    
    createNewImmutableStructWithModifiedFields(...)
end

```

Also the fields not included `fieldsToModify` should be duplicated from original struct.

Edit: from my understanding of @generated now it doesn’t seem like it would solve this particular problem

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 24, 2018, 12:24am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/5 "2018-06-24T00:24:10Z")

</div>

Thanks for the explanation that does help me understand but:

> [@chakravala](#):
>
> the value of `$foo` that gets interpolated is `:foo` , so `@eval` is calling `println(foo)` (since `:(println($(:foo)))` ), but then `foo` does not exist in that context.

In the global scope it seems to work ok?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 24, 2018, 7:59am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/6 "2018-06-24T07:59:21Z")

</div>

> [@anon32405968](#):
>
> I’ve gone over the @generated and AST docs several times to try and understand your suggestions, I was wondering if you might be able to give a small code example to demonstrate? Essentially, in (Julia-esque) pseudocode, what I’m trying to achieve is this:

`@generated` is not what you want you. You want to write a macro `@modifier this_struct :these :fields` that takes in those args and returns an expression for building the struct.

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 28, 2018, 10:24am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/7 "2018-06-28T10:24:55Z")

</div>

Thanks, I’m trying with a macro now. Sorry just a follow up to your first answer the bit I’m struggling to understand, if eval happens in the global scope how come this works ok?

```julia
function maintest()
    foo = "bar"
    @eval ($println)($foo)
end

maintest()
> bar

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [June 28, 2018, 10:57am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/8 "2018-06-28T10:57:45Z")

</div>

```julia
julia> @macroexpand @eval println($foo)
:((Base.Core).eval(Main, (Core._expr)(:call, :println, foo)))

```

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 28, 2018, 11:33am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/9 "2018-06-28T11:33:29Z")

</div>

It’s interpolating `foo` into the expression locally (interpolation is local) and then `eval`ing that expression.

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 28, 2018, 11:42am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/10 "2018-06-28T11:42:18Z")

</div>

ah ok I get it thanks! But what if I want something to be interpolated to a symbol, i.e. so I can use the ‘getfield’ function in an expression? I tried playing with ‘esc’ but that doesn’t seem to do the trick.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 28, 2018, 11:48am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/11 "2018-06-28T11:48:04Z")

</div>

Example?

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 28, 2018, 11:52am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/13 "2018-06-28T11:52:02Z")

</div>

Going back to a function for the sake of example, i think interpolating to a symbol is the crux of my problems, the rest I seem to have got working:

```julia

struct testhang

    a::Float64
    b::Float64
    c::Float64

end

function maintest(structy, symbolist)

    for (i, v) in enumerate(symbolist)
         @eval $v = ($getfield)($structy, $(esc(v)))
    end

end

insty = testhang(1.0, 2.0, 3.0)

maintest(insty, [:a, :b, :c])

```

**edit:** in other words, in the local namespace I want variables ‘a’, ‘b’ and ‘c’ to be set equal to ‘structy.a’, ‘structy.b’ and ‘structy.c’ respectively.

**edit:** woops sorry I know I’m missing the @eval, just put it in

**edit again:** fixed number of brackets

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [June 28, 2018, 11:55am UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/14 "2018-06-28T11:55:55Z")

</div>

`@eval` evaluates in global scope so you cannot use it to declare local variables.

You can use something like

```julia
julia> using Parameters

julia> struct Foo
           a
           b
           c
       end

julia> function f(f::Foo)
           @unpack a, b, c = f
           print(a, b, c)
       end
f (generic function with 1 method)

julia> f(Foo(1, 2, 3))
123

```

You would use a macro for your usecase but note that you can only construct it so that at expansion time the macro knows exactly what syntax to generate. So you need to fix the type or the fields to unpack before runtime.

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [June 28, 2018, 3:55pm UTC](https://discourse.julialang.org/t/struggling-to-understand-this-symbol-behaviour-scope-determines-error-presence/11891/15 "2018-06-28T15:55:27Z")

</div>

OK thanks, I see that now. And after some playing around I figured why the getfield wasn’t working. Will post code in case others read this thread and want to know. Realised that if you want to interpolate to the symbol value you have to wrap it in a `$(Expr(:quote, symvar))`.

So the code below basically does what I need as I don’t really mind that the variable is created in global scope.

```julia
struct foo
    a::Float64
    b::Float64
end

function modifyfoo(self::foo, tomodify::Array{Symbol,1})

    for symvar in tomodify
        @eval $symvar = ($getfield)($self, $(Expr(:quote, symvar)))
    end

end

instance = foo(0.0, 0.0)

modifyfoo(instance, [:a, :b])

println("From global\na: $a \nb: $b")

> From global
> a: 0.0
> b: 0.0

```
