# How use eval to define macros that involve function definitions

**URL:** <https://discourse.julialang.org/t/how-use-eval-to-define-macros-that-involve-function-definitions/93773>\
**Category:** General Usage\
**Tags:** macros, macro-hygiene\
**Created:** [January 30, 2023, 1:28pm UTC](https://discourse.julialang.org/t/how-use-eval-to-define-macros-that-involve-function-definitions/93773 "2023-01-30T13:28:51Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [January 30, 2023, 1:28pm UTC](https://discourse.julialang.org/t/how-use-eval-to-define-macros-that-involve-function-definitions/93773/1 "2023-01-30T13:28:51Z")

</div>

I want to define a bunch of macros that define function methods in a private module.

```julia
module MyModule

function f() end
function g() end

end

using Main.MyModule

struct T
    i
end

macro f(T, expr)
    esc(:(MyModule.f(::$T) = $expr))
end

@f T "test"

julia> MyModule.f(T(1))
"test"

```

That works fine if I do it manually. If I try to do this in an eval loop, if fails

```julia
for fn in (:f, :g)
    Core.eval(@ __MODULE__ , quote
        macro $fn(T, expr)
          esc(:($(MyModule.$fn)(::$T) = $expr))
        end
    end)
end

```

The macro call fails:

```julia
julia> @f T "test"
ERROR: syntax: invalid function name "MyModule.f" around REPL[36]:1
Stacktrace:
 [1] top-level scope
   @ REPL[36]:1

```

I played around with QuoteNodes, but I couldn’t solve this problem.  
It feels a bit similar like the discussion in [Can't initalize a function with no methods inside a macro · Issue #34164 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/34164)

Anyone who can help here?

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [October 19, 2024, 3:57pm UTC](https://discourse.julialang.org/t/how-use-eval-to-define-macros-that-involve-function-definitions/93773/2 "2024-10-19T15:57:38Z")

</div>

I assume the problem is due to the nested interpolations with `$`. For example, using `Meta.parse` you can write

```julia-repl
julia> for fn in (:f, :g)
           "macro $fn(T, expr)
               esc(:(MyModule.$fn(::\$T) = \$expr))
           end" |> Meta.parse |> eval
       end

julia> @g T "abc"

julia> MyModule.g(T(1))
"abc"

```

but note that I had to use both `$` and `\$`.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [October 19, 2024, 5:42pm UTC](https://discourse.julialang.org/t/how-use-eval-to-define-macros-that-involve-function-definitions/93773/3 "2024-10-19T17:42:43Z")

</div>

> [@hhaensel](#):
>
> ```julia
> function f() end
> function g() end
> 
> ```

Unrelated to your metaprogramming issue - you most probably want this instead:

```julia
function f end
function g end

```

`function f end` defines a function without methods, while `function f() end` defines a function with a single method.

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [October 19, 2024, 6:12pm UTC](https://discourse.julialang.org/t/how-use-eval-to-define-macros-that-involve-function-definitions/93773/4 "2024-10-19T18:12:58Z")

</div>

Inspired by the `Expr`ession obtained by the `Meta.parse` above, here’s a way to achieve this without resorting to `String`s:

```julia
for fn in (:f, :g)
    quote
        macro $fn(T, expr)
            $(Expr(:quote, esc(:(MyModule.$fn(::$(Expr(:$, T))) = $(Expr(:$, :expr))))))
        end
    end |> eval
end

```

i.e. use `Expr(:$, :x)` for the nested version of `$x`, and wrap this nesting in an `Expr(:quote, ...)`.
