# Using \`eval\` inside \`quote\`

**URL:** <https://discourse.julialang.org/t/using-eval-inside-quote/103505>\
**Category:** General Usage\
**Tags:** metaprogramming\
**Created:** [September 4, 2023, 12:18pm UTC](https://discourse.julialang.org/t/using-eval-inside-quote/103505 "2023-09-04T12:18:19Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![pat-alt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pat-alt/32/34264_2.png) [@pat-alt](https://discourse.julialang.org/u/pat-alt)\
**Post date:** [September 4, 2023, 12:18pm UTC](https://discourse.julialang.org/t/using-eval-inside-quote/103505/1 "2023-09-04T12:18:19Z")

</div>

I’ve recently added a new feature to [`CounterfactualExplanations.jl`](https://github.com/JuliaTrustworthyAI/CounterfactualExplanations.jl/releases/tag/v0.1.15) that adds support for multi-processing through [MPI](https://juliatrustworthyai.github.io/CounterfactualExplanations.jl/stable/tutorials/parallelization/#MPI). On the user-end, this is handled through a simple macro:

```julia
ces = @with_parallelizer parallelizer begin
    generate_counterfactual(
        xs,
        target,
        counterfactual_data,
        M,
        generator
    )
end

```

Now I realised that this causes an issue for keyword arguments that are passed to `generate_counterfactual` as `Symbol`s, because they are turned into `QuoteNodes` inside the macro, e.g.

```julia
ces = @with_parallelizer MPIParallelizer() begin
    generate_counterfactual(
        xs,
        target,
        counterfactual_data,
        M,
        generator;
        initialization=:identity
    )
end

```

throws an error:

```julia
╭──────────────────────────────────────────────────────────────── TypeError ───────────────────────────────────────────────────────────────╮
│ │
│ TypeError: in keyword argument initialization, expected Symbol, got a value of type QuoteNode │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

```

In this [PR](https://github.com/JuliaTrustworthyAI/CounterfactualExplanations.jl/pull/288) I’ve added a fix that relies on call `eval` on the `QuoteNode` inside the final `quote` that is returned by the macro:

```julia
macro with_parallelizer(parallelizer, expr)
    
    [...]

    # Parallelize:
    output = quote
        @assert CounterfactualExplanations.parallelizable($f) "`f` is not a parallelizable process."
        kws = [Pair(k, typeof(v) == QuoteNode ? eval(v) : v) for (k, v) in $aakws]
        output = CounterfactualExplanations.parallelize($pllr, $f, $escaped_args...; kws...)
        output
    end
    return output
end

```

This feels dodgy (as do most things when I dare to write a macro) but if I understand the following section of the docs on [macro hygiene](https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene) correctly, it is fine/standard?

> […] For example, many macros simply wrap their arguments in a `QuoteNode` or other similar [`Expr`](https://docs.julialang.org/en/v1/base/base/#Core.Expr). Some examples of this include `@task body` which simply returns `schedule(Task(() -> $body))` , and `@eval expr` , which simply returns `eval(QuoteNode(expr))` .

Is this indeed fine? If not, any suggestions as to how I can deal with the `QuoteNode` or improve/avoid the macro altogether?

Thanks!

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [September 4, 2023, 12:35pm UTC](https://discourse.julialang.org/t/using-eval-inside-quote/103505/2 "2023-09-04T12:35:28Z")

</div>

> [@pat-alt](#):
>
> This feels dodgy (as do most things when I dare to write a macro) but if I understand the following section of the docs on [macro hygiene](https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene) correctly, it is fine/standard?

> [@pat-alt](#):
>
> Is this indeed fine? If not, any suggestions as to how I can deal with the `QuoteNode` or improve/avoid the macro altogether?

In general no - the only reason `@eval` has an `eval` is because that’s what it does (this is not circular logic - `@eval` is quite literally an `eval`). Macros generally shouldn’t need to `eval`.

What you’d really want to do is create the entire expression for that final call:

```julia
CounterfactualExplanations.parallelize($pllr, $f, $escaped_args...; kws...)

```

and just give it the keywords part of the initial expression. You can get only those keywords already by checking the second argument of the call expression:

```julia
julia> Meta.@dump f(a,b; c=:d)
Expr
  head: Symbol call
  args: Array{Any}((4,))
    1: Symbol f
    2: Expr
      head: Symbol parameters
      args: Array{Any}((1,))
        1: Expr
          head: Symbol kw
          args: Array{Any}((2,))
            1: Symbol c
            2: QuoteNode
              value: Symbol d
    3: Symbol a
    4: Symbol b

```

* * *

A bit of an orthogonal note - `@assert` is not guaranteed to run at all optimization levels. See also its [docstring](https://docs.julialang.org/en/v1/base/base/#Base.@assert). So checks like [here](https://github.com/JuliaTrustworthyAI/CounterfactualExplanations.jl/pull/288/files#diff-84c2f883efea86666c90bb57c0774c7f1836c23672226d1a639ae682ae04c264R17) or [here](https://github.com/JuliaTrustworthyAI/CounterfactualExplanations.jl/pull/288/files#diff-84c2f883efea86666c90bb57c0774c7f1836c23672226d1a639ae682ae04c264R45) really ought to use a proper conditional & `throw`.

---

<div class="post-metadata">

**Author:** ![pat-alt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pat-alt/32/34264_2.png) [@pat-alt](https://discourse.julialang.org/u/pat-alt)\
**Post date:** [September 4, 2023, 1:33pm UTC](https://discourse.julialang.org/t/using-eval-inside-quote/103505/3 "2023-09-04T13:33:47Z")

</div>

Thanks very much @Sukera for the quick response. I’m not sure this exactly what you had in mind but your MWE has given me an idea how to avoid `eval` by just retrieving the value from the `QuoteNode` before defining the `quote` (see [here](https://github.com/JuliaTrustworthyAI/CounterfactualExplanations.jl/pull/288/commits/e39e4b9036da39e61516eeb6b58d379064c35c76)). Still feels somewhat hacky but hopefully that’s a cleaner/safer approach.

I’ve also fixed the `@assert`, thanks for flagging.

Thanks!
