# Macro interpolation of Symbols without \`eval\`

**URL:** <https://discourse.julialang.org/t/macro-interpolation-of-symbols-without-eval/117603>\
**Category:** General Usage\
**Tags:** question, metaprogramming\
**Created:** [July 29, 2024, 4:53pm UTC](https://discourse.julialang.org/t/macro-interpolation-of-symbols-without-eval/117603 "2024-07-29T16:53:00Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![joh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joh/32/34773_2.png) [@joh](https://discourse.julialang.org/u/joh)\
**Post date:** [July 29, 2024, 4:53pm UTC](https://discourse.julialang.org/t/macro-interpolation-of-symbols-without-eval/117603/1 "2024-07-29T16:53:00Z")

</div>

I am trying to write a macro for setting up a submodule in my package. Since this is called at precompile time, I cannot use `eval` (otherwise I get `InitError: Evaluation into the closed module ImportEval breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating ImportEval with eval during precompilation - don't do this.`  
I set up a minimal example to illustrate where I am struggling:

```julia
a, b, c = 1, 2, 3
macro showvars(vars...)
    quote
        for v in $(esc(vars))
            # 1) desired output, but eval prohibited
            println("$v = ", eval(v))

            # 2) not desired output
            println("$v = ", v)

            # 3) errors: 'UndefVarError: `v` not defined'
            # println("$v = ", $v)

            # 4) does not work: for-loop only generates quotes
            quote
                println("$v = ", $v)
            end

            # 5) does not work: same as 2.
            $(quote
                println("$v = ", v)
            end)
        end
    end
end
@showvars c a

```

The desired output is

```julia
c = 3
a = 1

```

Is it possible to achieve the same behavior as in 1) without using `eval` somehow? I know I can do it by explicitly constructing the appropriate expression with `Expr(...)` but I feel there should be an easier, more readable way to do it.

---

<div class="post-metadata">

**Author:** ![WschW](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wschw/32/6575_2.png) [@WschW](https://discourse.julialang.org/u/WschW)\
**Post date:** [July 29, 2024, 8:26pm UTC](https://discourse.julialang.org/t/macro-interpolation-of-symbols-without-eval/117603/3 "2024-07-29T20:26:37Z")

</div>

If the variables are on the top level then you can use `getfield` to get the value from the module, IIRC.

---

<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:** [July 29, 2024, 9:10pm UTC](https://discourse.julialang.org/t/macro-interpolation-of-symbols-without-eval/117603/4 "2024-07-29T21:10:56Z")

</div>

As macros work on expressions, you will need to insert the variables – and not just their names as in your for loop – into the expression generated by the macro. Thus, instead of generating a for loop – which would then run when executed – you could unroll the loop and generate the desired calls to `println` directly, i.e., here is a working macro for your minimal example:

```julia
macro showvars(vars...)
    unrolled = [:(println("$($(QuoteNode(v))) = ", $(esc(v)))) for v in vars]
    quote
        $(unrolled...)
    end
end

```

When writing macros it helps a lot to check the expansion, i.e.,

```julia-repl
julia> @macroexpand1 @showvars c a
quote
    #= REPL[72]:4 =#
    Main.println("$(:c) = ", c)
    Main.println("$(:a) = ", a)
end

```

---

<div class="post-metadata">

**Author:** ![joh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joh/32/34773_2.png) [@joh](https://discourse.julialang.org/u/joh)\
**Post date:** [July 30, 2024, 12:37pm UTC](https://discourse.julialang.org/t/macro-interpolation-of-symbols-without-eval/117603/5 "2024-07-30T12:37:57Z")

</div>

Thanks, that was very helpful and solves the problem I described! I don’t fully understand when to use `QuoteNode` and `esc`, yet.

There is one more thing I need which is that `vars` is not a tuple of Symbols but an expression describing a tuple. That is, the macro should be called like this:

```julia
macro showvars(vars) end
@showvars (c, a)

```

The reason is that in my application, it will receive multiple tuples of symbols that are handled differently, e.g. `@mymacro (a, b) (c, d)`.  
I am able to do what I need to by using `tupleexpr.args` in the same way as `vars` in your unrolled loop, but maybe there is a nicer solution I was not able to find.
