# Macro hygiene in nested quote not working

**URL:** <https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806>\
**Category:** Performance\
**Tags:** question\
**Created:** [November 21, 2018, 8:50am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806 "2018-11-21T08:50:17Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 8:50am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/1 "2018-11-21T08:50:17Z")

</div>

unfortunately I face severe problems when dealing with macros with nested quotes. Somehow the standard hygiene does not seem to work… three examples, all failing

# first experiment .. fails

```julia-auto
module NestedQuoteHygiene
  export @hygienetest

  macro hygienetest()
    quote
      function a end # hygiene
      nestedquote = quote
        println(a) # no hygiene, i.e. refers to another a
      end
      (nestedquote, a)
    end
  end
end

```

when running this macro test, you can see that the `a` within the nested quote is not renamed accordingly

```juliarepl
julia> NestedQuoteHygiene.@hygienetest
(quote
    println(a)
end, #8#a)

```

What do I do wrong?  
**I really want to refer to the `a` function defined in the macro, i.e. `#8#a`**

# second experiment … failing

I made a second test which looks even more surprising - this is interpolating `a` now

```julia-auto
module NestedQuoteHygiene2
  export @hygienetest2

  macro hygienetest2()
    quote
      function a end # hygiene
      nestedquote = quote
        println($a) # no hygiene, i.e. refers to another a
      end
      (nestedquote, a)
    end
  end
end

```

run it like

```julia-auto
julia> a = 4
4

julia> NestedQuoteHygiene2.@hygienetest2
(quote
    println(4)
end, #8#a)

```

that looks really bad… any idea?

# third experiment… also failing

```julia-auto
module NestedQuoteHygiene3
  export @hygienetest3

  macro hygienetest3()
    quote
      function a end # hygiene
      symbol_a = Symbol(a)
      nestedquote = quote
        println($symbol_a) # ERROR: UndefVarError: symbol_a not defined
      end
      (nestedquote, a)
    end
  end
end

```

```julia-auto
julia> NestedQuoteHygiene3.@hygienetest3
ERROR: UndefVarError: symbol_a not defined

```

anyone who can help?  
EDIT Clarification of Goal: **I want to refer to `function a end` from the inner quote**

any help is highly appreciated… this really blocks me currently

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 21, 2018, 9:59am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/3 "2018-11-21T09:59:57Z")

</div>

Try to `macroexpand` and you will see the problem. In particular, are you after

```julia
module NestedQuoteHygiene
macro hygienetest()
    quote
        function a end # hygiene
        nestedquote = quote
            println($(esc(:a))) # no hygiene, i.e. refers to another a
        end
        (nestedquote, a)
    end
end
end

```

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 11:22am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/4 "2018-11-21T11:22:12Z")

</div>

thanks for helping!

Have you tried your suggestion?  
When I am executing it I get `ERROR: syntax: invalid syntax (escape (outerref a))`

```julia
julia> nestedquote, f = NestedQuoteHygiene.@hygienetest
(quote
    #= REPL[1]:11 =#
    println($(Expr(:escape, :a)))
end, #10#a)

julia> eval(nestedquote)
ERROR: syntax: invalid syntax (escape (outerref a))
Stacktrace:
 [1] eval at .\boot.jl:319 [inlined]
 [2] eval(::Expr) at .\client.jl:389
 [3] top-level scope at none:0

```

also `@macroexpand` does not look good either

```julia
 @macroexpand NestedQuoteHygiene.@hygienetest
quote
    #= REPL[1]:7 =#
    function #12#a end
    #= REPL[1]:9 =#
    #13#nestedquote = (Core._expr)(:block, $(QuoteNode(:(#= REPL[1]:11 =#))), (Core._expr)(:call, :p
rintln, esc(:a)))
    #= REPL[1]:15 =#
    (#13#nestedquote, #12#a)
end

```

seems still unsolved unfortunately…

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 21, 2018, 11:29am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/5 "2018-11-21T11:29:07Z")

</div>

> [@schlichtanders](#):
>
> also `@macroexpand` does not look good either

Then I misunderstood your specs, can you please tell us what you would like to see in the expanded macro?

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 11:43am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/6 "2018-11-21T11:43:41Z")

</div>

I would like to refer to the `function a end` I am bit astonished, that this was not clear  
however as this `a` gets `Base.gensym` to `#12#a` or similar, your escaping does not seem to work

as you see, I run your code and it just fails with the described message.  
Also your `@macroexpand` shows an `esc(:a)` while the outer `function a end` is already renamed to `function #12#a end`

so ideally I want

```julia
@macroexpand IdealNestedQuoteHygiene.@idealhygienetest
quote
    #= REPL[1]:7 =#
    function #12#a end
    #= REPL[1]:9 =#
    #13#nestedquote = (Core._expr)(:block, $(QuoteNode(:(#= REPL[1]:11 =#))), (Core._expr)(:call, :p
rintln, #12#a)))
    #= REPL[1]:15 =#
    (#13#nestedquote, #12#a)
end

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 21, 2018, 11:56am UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/7 "2018-11-21T11:56:32Z")

</div>

I think that

```julia
module NestedQuoteHygiene
macro hygienetest()
    a = gensym(:a)
    quote
        function $(a) end # hygiene
        nestedquote = quote
            println($$(a)) # no hygiene, i.e. refers to another a
        end
        (nestedquote, $a)
    end
end
end

```

should do what you want, ie

```julia
julia> macroexpand(Main, :(NestedQuoteHygiene.@hygienetest))
quote
    #= REPL[6]:5 =#
    function #14###a#358 end
    #= REPL[6]:6 =#
    #15#nestedquote = (Core._expr)(:block, $(QuoteNode(:(#= REPL[6]:7 =#))), (Core._expr)(:call, :println, ##a#358))
    #= REPL[6]:9 =#
    (#15#nestedquote, #14###a#358)
end

```

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 12:38pm UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/8 "2018-11-21T12:38:00Z")

</div>

lovely straightforward solution!  
thank you so much!

still I am surprised that this is not easily possible by using “normal” macro hygiene.  
Does someone know why julia implemented macro expansion of nested quotes the way it does?  
Or does someone know where the code is for the macro expansion?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 21, 2018, 12:47pm UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/9 "2018-11-21T12:47:56Z")

</div>

> [@schlichtanders](#):
>
> still I am surprised that this is not easily possible by using “normal” macro hygiene.

Macro hygiene is automatically replacing symbols, (AFAIK) there is no API for accessing the generated symbols during expansion.

> [@schlichtanders](#):
>
> Does someone know why julia implemented macro expansion of nested quotes the way it does?

I don’t think there is anything special about nested quotes here (except that you have to `$` twice to get to the outer-outer value).

> [@schlichtanders](#):
>
> Or does someone know where the code is for the macro expansion?

[macroexpand.scm](https://github.com/JuliaLang/julia/blob/464397e7141d744cb95da8f9b3e8b1d5c7062b9f/src/macroexpand.scm)

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 12:52pm UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/10 "2018-11-21T12:52:13Z")

</div>

thank you very very much for all the effort, time, and helpful answers!

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 1:01pm UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/11 "2018-11-21T13:01:15Z")

</div>

still not complete…

the trick with assignments using `Base.gensym` does not work if you use it again as an assinment place…  
It gets gensymed twice in the outer quote and gensymed once in the inner quote, again leaving me with incompatibility.

```julia
module MyTest
  macro mytest()
    a = gensym(:a)
    quote
      $a = 42
      nestedquote = quote
        println($$a)
      end
      (nestedquote, $a)
    end
  end
end

```

```julia
julia> @macroexpand MyTest.@mytest
quote
    #12###a#362 = 42
    #13#nestedquote = (Core._expr)(:block, $(QuoteNode((Core._expr)(:call, :println, ##a#362))
    (#13#nestedquote, #12###a#362)
end

```

---

<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 21, 2018, 1:01pm UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/12 "2018-11-21T13:01:57Z")

</div>

See also [https://github.com/JuliaLang/julia/pull/6910](https://github.com/JuliaLang/julia/pull/6910).

Also, you can do hygiene the other way round too: escape everything and use gensym when hygiene is needed.

PS: good to see that you’re working on traits 😉

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 21, 2018, 1:07pm UTC](https://discourse.julialang.org/t/macro-hygiene-in-nested-quote-not-working/17806/13 "2018-11-21T13:07:15Z")

</div>

thanks for the issue link

I see, makes sense! if I escape everything, no extra renamings happen. Makes sense!

```julia
module MyTest
  macro mytest()
    a = gensym(:a)
    esc(quote
      $(a) = 42
      nestedquote = quote
        println($$a)
      end
      (nestedquote, $a)
    end)
  end
end

```

works as hoped for

```julia
quote
    #= none:5 =#
    ##a#365 = 42
    #= none:6 =#
    nestedquote = (Core._expr)(:block, $(QuoteNode(:(#= none:7 =#))), (Core._expr)(:call, :println,
##a#365))
    #= none:9 =#
    (nestedquote, ##a#365)
end

```

PS: 😉 I am almost there
