# Macro hygene escape puzzle

**URL:** <https://discourse.julialang.org/t/macro-hygene-escape-puzzle/51588>\
**Category:** General Usage\
**Created:** [December 10, 2020, 5:13am UTC](https://discourse.julialang.org/t/macro-hygene-escape-puzzle/51588 "2020-12-10T05:13:44Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![thisrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thisrod/32/10642_2.png) [@thisrod](https://discourse.julialang.org/u/thisrod)\
**Post date:** [December 10, 2020, 5:13am UTC](https://discourse.julialang.org/t/macro-hygene-escape-puzzle/51588/1 "2020-12-10T05:13:44Z")

</div>

I want to define a macro similar to those in the code below, where the function `f` is evaluated in the scope where the macro is expanded, but `default` is evaluated in module `A`.

```
               _
   _ _ _(_)_ | Documentation: https://docs.julialang.org
  (_) | (_) (_) |
   _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` | |
  | | |_| | | | (_| | | Version 1.5.3 (2020-11-09)
 _/ |\ __'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |

julia> module A
macro p() quote $(esc(:f))(x=default) = 1 end end
macro q() quote function $(esc(:f)) end end end
macro r() quote function $(:f) end end end
macro s() quote f(x=default) = 1 end end
macro t() :( f(x=default) = 1 ) end
end
Main.A

julia> using .A: @p, @q, @r, @s, @t

julia> @macroexpand @p
quote
    #= none:2 =#
    f(var"#1#x" = Main.A.default) = begin
            #= none:2 =#
            1
        end
end

julia> @macroexpand @s
quote
    #= none:5 =#
    var"#2#f"(var"#3#x" = Main.A.default) = begin
            #= none:5 =#
            1
        end
end

```

This is consistent with the manual. Defining `f` as a function is like assigning to it, so it’s a local variable. (It would be nice if the manual said that explicitly.) Unless it is escaped, it is replaced by a gensym.

```
julia> @macroexpand @q
:($(Expr(:error, "malformed expression")))

julia> @macroexpand @r
quote
    #= none:4 =#
    function var"#4#f" end
end

```

That’s odd: `esc(:f)` works in some contexts, but not in others. Is there a way to do what `@q` is trying to do?

```
julia> @macroexpand @t
:(Main.A.f(var"#5#x" = Main.A.default) = begin
          #= none:6 =#
          1
      end)

```

That’s also odd. By my reading of the manual, `f` should refer to the same thing in `@t` as it does in `@s`.

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [December 10, 2020, 7:08am UTC](https://discourse.julialang.org/t/macro-hygene-escape-puzzle/51588/2 "2020-12-10T07:08:16Z")

</div>

The difference between `@s` and `@t` looks like a bug to me. From the documentation of `quote`:

```julia
  Unlike the other means of quoting, :( ... ), this form introduces QuoteNode elements to the
  expression tree, which must be considered when directly manipulating the tree. For other purposes,
  :( ... ) and quote .. end blocks are treated identically.

```

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [December 10, 2020, 9:05am UTC](https://discourse.julialang.org/t/macro-hygene-escape-puzzle/51588/3 "2020-12-10T09:05:31Z")

</div>

> [@thisrod](#):
>
> ```julia
> julia> @macroexpand @q
> :($(Expr(:error, "malformed expression")))
> 
> ```

This is a known issue and should be fixed on Julia nightly. See [fix #38386, macro defining empty function with escaped name by JeffBezanson · Pull Request #38402 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/38402)
