# Interpolating variable to expr to be used in macro

**URL:** https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785
**Category:** General Usage
**Created:** [March 18, 2024, 5:26pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785 "2024-03-18T17:26:30Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)
#### Post date: [March 18, 2024, 5:26pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/1 "2024-03-18T17:26:30Z")

</div>

I want to write a macro that calls 2 macros. The second macro depends on the first macro. The first macro returns an expression that I want to pass to the second macro and I am unsure how to do this. See a simplified example. (Note: first macro is @code\_expr)

```julia
julia> using Revise, CodeTracking, Handcalcs

julia> macro macro_main(expr)
           return quote
               found_func = @code_expr calc_Ix(5, 15)
               latex = @mac2 found_func
           end
       end
@macro_main (macro with 1 method)

julia> macro mac2(expr)
       quote foo($expr)
       end
       end
@mac2 (macro with 1 method)

julia> function foo(ex) # this is simplified, but the function builds an expression
       len = length(ex.args)
       return Expr(:(=), :x, len)
       end
foo (generic function with 1 method)

julia> @macro_main calc_Ix(5, 15) # calc_Ix defined in Handcalcs
:(x = 2)

```

You can see the way I wrote `@mac2` allowed me to interpolate the `found_func` variable in `@macro_main`. However, this returns an expression `:(x = 2)` rather than the evaluated expression since I have to put it inside a quote block.

How do I get, in this simplified example, the expression evaluated, so when I do:

```julia
julia> x
2

```

I get 2.

I have tried multiple ways so far and I always end up with just the unevaluated expression, or having to use the eval function which only allows the macro to work within the global scope.

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [March 18, 2024, 9:14pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/2 "2024-03-18T21:14:20Z")

</div>

It is unclear to me why `@mac2` needs to be a macro. The way you have written it right now `@mac2` only ever gets the symbol `found_func`. It appears to me that you want to have the _contents_ of `found_func` to be passed to the inside of `@mac2` and then to the function `foo`.  
So you should just make `@mac2` a normal function and remove the quote inside it (and then you could also remove it alltogether and just have `@macro_main` expand to a call to foo).

---

<div class="post-metadata">

### Author: ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)
#### Post date: [March 18, 2024, 11:40pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/3 "2024-03-18T23:40:24Z")

</div>

I need info from `@code_expr ` though which happens at macro expansion time, so it would not expand again on the call to foo. That is why I believe I need another macro, `@mac2`.

I currently do not have `@mac2` (in my working code) and have been trying within `@macro_main` and I just get the unevaluated expression. The only way I get it “working” is by using the `eval` function or macro, but it only allows it to work within a global scope. The `@mac2` way was sort of my next idea… but still can’t get it working.

---

<div class="post-metadata">

### Author: ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)
#### Post date: [March 18, 2024, 11:57pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/4 "2024-03-18T23:57:01Z")

</div>

I should have written `found_func` in the `@macro_main` a bit different. See below:

```Julia
julia> macro macro_main(expr)
           return quote
               found_func = @code_expr $expr
               latex = @mac2 found_func
           end
       end

julia> a = 5
5

julia> b = 15
15

julia> @macro_main calc_Ix(a, b) # calc_Ix defined in Handcalcs
:(x = 2)

```

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [March 19, 2024, 7:55am UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/5 "2024-03-19T07:55:13Z")

</div>

> [@co1emi11er](#):
>
> ```julia
> macro macro_main(expr)
> return quote
> found_func = @code_expr $expr
> latex = @mac2 found_func
> end
> end
> 
> ```

This does not pass anything from `@code_expr` to `@mac2` though. All macros are expanded before anything is evaluated. Thus `@mac2` only ever gets the symbol `:found_func` as argument and never its runtime value.

I don’t think what you plan can be realised just with macros in a simple way, because some information (like the types of `a` and `b`) is available only at runtime. Thus `code_expr` can only find the correct method at runtime. After that it is too late to go back to macro expansion.

~~So macros are not the answer but I think you can use a generated function instead since they have access to the types (but not the values) of things. We also take some inspiration from `@code_expr`.~~

_This does not work because you cannot use reflection from inside of generated function. So I don’t know how your goal can be achieved. Sorry._ 😕

For completeness, here is my non-functional draft:

```julia
macro macro_main(ex0...)
    # if you want to do something with the return value of gen_func
    # generate more complicated stuff here
    InteractiveUtils.gen_call_with_extracted_types_and_kwargs( __module__ , :gen_func, ex0)
end
@generated function gen_func(f::F, types) where F
    # types is Type{Tuple{argtype1,argtype2,...}} we need to convert it to (argtype1,...)
    argtype_tuple = tuple(types.parameters[1].types...)
    # line below does not work because it uses reflection!
    found_func = code_expr(f, argtype_tuple) # use type information to get the function
    # now generate the body that you want to execute
    return :(foo($found_func))
end

```

To summarize: I think what you want to do is impossible in general. The problem is you need to do reflection which only works at runtime (since function definitions are only meaningful at runtime) but then still want to do some level of code generation depending on that information from reflection.

---

<div class="post-metadata">

### Author: ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)
#### Post date: [March 19, 2024, 1:18pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/6 "2024-03-19T13:18:22Z")

</div>

> [@abraemer](#):
>
> This does not pass anything from `@code_expr` to `@mac2` though. All macros are expanded before anything is evaluated. Thus `@mac2` only ever gets the symbol `:found_func` as argument and never its runtime value.

Yeah I was hoping to do something like the @eval macro does where it interpolates. See below:

```Julia
julia> let y = 7
           z = @eval $y
       end
end
7

```

But I can’t figure out how to do this inside a quote. See below:

```Julia
julia> quote
       let y = 7
           z = @eval $y
       end
       end
ERROR: UndefVarError: `y` not defined
Stacktrace:
 [1] top-level scope
   @ REPL[46]:1

```

> [@abraemer](#):
>
> _So I don’t know how your goal can be achieved. Sorry._ 😕

Yeah I am getting to this point too… There is something in my gut though that is telling me that it should be possible. Thanks for the help!

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [March 19, 2024, 1:54pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/7 "2024-03-19T13:54:19Z")

</div>

> [@co1emi11er](#):
>
> But I can’t figure out how to do this inside a quote

You can figure this out by inspecting the AST:

```julia-repl
julia> dump(:(:($x)))
Expr
  head: Symbol quote
  args: Array{Any}((1,))
    1: Expr
      head: Symbol $
      args: Array{Any}((1,))
        1: Symbol x

julia> quote
              let y = 7
                  z = @eval $(Expr(:$, :y))
              end
       end
quote
    #= REPL[14]:2 =#
    let y = 7
        #= REPL[14]:3 =#
        z = #= REPL[14]:3 =# @eval($(Expr(:$, :y)))
    end
end

julia> macro testm()
       quote
              let y = 7
                  z = @eval $(Expr(:$, :y))
              end
       end
       end
@testm (macro with 1 method)

julia> @testm
7

```

But I still think this will not work if you try to get runtime information at macro expansion time. Simply because at macro expansion the runtime information does not exist yet. I don’t see how this interpolation will help you in that regard.

---

<div class="post-metadata">

### Author: ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)
#### Post date: [March 19, 2024, 2:35pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/8 "2024-03-19T14:35:44Z")

</div>

I think we are close. See below:

```Julia
julia> macro macro_main(expr)
           return quote
               found_func = @code_expr $expr
               latex = @eval @mac2 $(Expr(:$, :found_func))
           end
       end
@macro_main (macro with 1 method)

julia> @macro_main calc_Ix(a, b) # calc_Ix defined in Handcalcs
2

```

However, variables in a local scope do not work:

```Julia
julia> let u=4, v = 15
       @macro_main calc_Ix(u, v)
       end
ERROR: UndefVarError: `u` not defined
Stacktrace:
 [1] macro expansion
   @ REPL[47]:3 [inlined]
 [2] top-level scope
   @ REPL[50]:2

```

I think there may be something here though.

---

<div class="post-metadata">

### Author: ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)
#### Post date: [March 19, 2024, 2:41pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/9 "2024-03-19T14:41:18Z")

</div>

I think I may have it. I will try to implement in actual package. See below:

```Julia
julia> macro macro_main(expr)
           return esc(quote
               found_func = @code_expr $expr
               latex = @eval @mac2 $(Expr(:$, :found_func))
           end)
       end
@macro_main (macro with 1 method)

julia> let u=4, v = 15
       @macro_main calc_Ix(u, v)
       end
2

```

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [March 19, 2024, 2:52pm UTC](https://discourse.julialang.org/t/interpolating-variable-to-expr-to-be-used-in-macro/111785/10 "2024-03-19T14:52:21Z")

</div>

> [@co1emi11er](#):
>
> ```julia
> macro macro_main(expr)
> return esc(quote
> found_func = @code_expr $expr
> latex = @eval @mac2 $(Expr(:$, :found_func))
> end)
> end
> 
> ```

This leaks the variables `found_func` and `latex` to the outer scope. Better escape the relevant parts only:

```julia
macro macro_main(expr)
           return quote
               found_func = $(esc(:(@code_expr $expr)))
               latex = @eval @mac2 $(Expr(:$, :found_func))
           end
       end

```
