# Constructing expressions with local macro variables and Symbols

**URL:** <https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906>\
**Category:** General Usage\
**Tags:** macros\
**Created:** [November 22, 2021, 6:25pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906 "2021-11-22T18:25:49Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 22, 2021, 6:25pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/1 "2021-11-22T18:25:50Z")

</div>

I want to construct an expression inside a macro, given a particular input parameter.

The behavior should be like that:

```julia
julia> @macroexpand @mymacro mysym[15]
:([[:mysym], 15])

```

So I tried to write something like that:

```julia
macro mymacro(ex)
    return :([[:$(ex.args[1]) ], $(ex.args[2]) ])
end
# but this gave me:
julia> @macroexpand @mymacro mysym[15]
:([[(:$)((Main.ex).args[1])], 15])

```

I am really having trouble to understand this output.  
`ex.args[2]` evaluated perfectly as intended to `15`.  
But `ex.args[1]` is searching to be evaluated in the `Main` module. I don’t want that. I just want `ex` to be evaluated locally inside the macro.

I reached close when I escaped `ex.args[1]`, although I didn’t quite understood why, since I was thinking of the `esc()` as the way to access user namespace:

```julia
macro mymacro(ex)
    return :([[$(esc(ex.args[1])) ], $(ex.args[2]) ])
end
# so now only the `:` is missing
julia> @macroexpand @mymacro mysym[15]
:([[mysym], 15])

```

But adding the `:` really destroys everything:

```julia
macro mymacro(ex)
    return :([[:($(esc(ex.args[1]))) ], $(ex.args[2]) ])
end
julia> @macroexpand @mymacro mysym[15]
:([[Main.esc((Main.ex).args[1])], 15])

```

I finally got it working with

```julia
macro mymacro2(ex)
    return Expr(:vect, Expr(:vect, QuoteNode(ex.args[1])), ex.args[2])
end

```

But that was quite hard and unintuitive to construct.  
Can there be a simpler solution using `:(....)` like in my first attempts?

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 22, 2021, 7:05pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/2 "2021-11-22T19:05:51Z")

</div>

Do you really want a quoted expression, or just the literal vector?

```julia
macro mymacro(ex)
   [[esc(ex.args[1])],ex.args[2]]
end

```

?

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 22, 2021, 7:18pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/3 "2021-11-22T19:18:57Z")

</div>

I really want a quoted expression.  
The reason is using it to build a macro for evaluating JuMP variables.  
e.g.

```julia
julia> @macroexpand @val myvar[(14,53)]
:((model[:myvar])[(14,53)] |> OptNetILPs.value)

```

I just constructed a minimal problem out of it.

As said, I did implemented it using expressions:

```julia
"evaluate indexed variable for JuMP model `model`"
macro val(ex::Expr)
    Expr(:call, :|>, Expr(:ref, Expr(:ref, esc(:model), QuoteNode(ex.args[1])), ex.args[2]), :value)
end

"evaluate single variable for JuMP model `model`"
macro val(sy::Symbol)
    Expr(:call, :|>, Expr(:ref, esc(:model), QuoteNode(sy)), :value)
end

```

But I find it quite complicated and I don’t understand why the `:(...)` doesn’t work, as mentioned above.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 22, 2021, 7:23pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/4 "2021-11-22T19:23:48Z")

</div>

Yeah, I’ve been fiddling around with it… I think you want:

```julia
macro mymacro(ex)
   return :([[$(esc(ex.args[1])) ], $(ex.args[2]) ])
end
@macroexpand @mymacro mysym[15]
:([[mysym], 15])

```

??

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [November 22, 2021, 7:26pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/5 "2021-11-22T19:26:57Z")

</div>

as a general principle of operation, macros are not designed to be composable, they are fundamentally different from functions. Thus, if you find something really useful, maybe try file an [Feature] issue on Github and see if they can add this to existing macros.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 22, 2021, 7:30pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/6 "2021-11-22T19:30:45Z")

</div>

> [@dlakelan](#):
>
> ```julia
> @macroexpand @mymacro mysym[15]
> :([[mysym], 15])
> 
> ```

I think the issue is you’re asking for a quote around mysym, but are you sure you need that? mysym is a symbol, quoting a symbol is not necessary normally.

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 22, 2021, 7:53pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/7 "2021-11-22T19:53:38Z")

</div>

This is exactly what I tried here:

> [@filchristou](#):
>
> ```julia
> macro mymacro(ex)
> return :([[$(esc(ex.args[1])) ], $(ex.args[2]) ])
> end
> 
> ```

But as you also mentioned, it gives out `:([[mysym], 15])` rather the desired `:([[:mysym], 15])`.

> [@dlakelan](#):
>
> I think the issue is you’re asking for a quote around mysym, but are you sure you need that? mysym is a symbol, quoting a symbol is not necessary normally.

`mysym` in `:([[mysym], 15])` will only be a literal, not a symbol.  
When the returning expression will be evaluated, it will not know to evaluate `mysym` as `Symbol("mysym")`

You can see the difference like that:

```julia
# mysym is a literal
julia> :([[mysym], 15]) |> eval
ERROR: UndefVarError: mysym not defined

# mysym is a symbol
julia> :([[:mysym], 15]) |> eval
2-element Vector{Any}:
   [:mysym]
 15

```

> [@jling](#):
>
> as a general principle of operation, macros are not designed to be composable, they are fundamentally different from functions. Thus, if you find something really useful, maybe try file an [Feature] issue on Github and see if they can add this to existing macros.

You mean the [Julia repository](https://github.com/JuliaLang/julia) ??  
I am even having trouble expressing the possible feature in question here. 😅

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [November 22, 2021, 7:58pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/8 "2021-11-22T19:58:29Z")

</div>

> [@filchristou](#):
>
> ```julia
> # mysym is a symbol
> julia> :([[:mysym], 15]) |> eval
> 2-element Vector{Any}:
> [:mysym]
> 15
> 
> ```

Here you’re saying you want the literal vector, so then:

```julia
macro mymacro(ex)
   return [[$(esc(ex.args[1]))],$(ex.args[2])]
end

```

I’m having a hard time understanding how you use the output of this macro and hence what the macro should actually output. I think the reason you’re having trouble is that you’re outputting something that’s really unusual, it’s a quote node containing another quote node.

When the macro returns should it be giving you:

```julia
quote
  [[quote mysym end],15]
end

```

or should it be giving you

```julia
[[mysym],15]

```

?  
And if it’s the first and not the second, is that because you plan to call eval on it? in which case it just becomes the second one except evaluated at top level?

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 22, 2021, 8:08pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/9 "2021-11-22T20:08:47Z")

</div>

> [@dlakelan](#):
>
> Here you’re saying you want the literal vector, so then:
> 
> ```julia
> macro mymacro(ex)
> return [[$(esc(ex.args[1]))],$(ex.args[2])]
> end
> 
> ```

This is the same as before but without quoting since giving:  
`ERROR: LoadError: syntax: "$" expression outside quote around /u/home/wima/fchrstou/code/julia/test/macro.jl:18`

Sorry for not being super clear.  
This is the desired behavior:

> [@filchristou](#):
>
> The behavior should be like that:
> 
> ```julia
> julia> @macroexpand @mymacro mysym[15]
> :([[:mysym], 15])
> 
> ```

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [November 22, 2021, 8:14pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/10 "2021-11-22T20:14:13Z")

</div>

Let me first say that I fully support what @jling said about macros not being composable, and that I would advise you to try and avoid having to use macros in this case.

That being said, as you found out, `QuoteNode` is the key here, as it allows you to build a quoted symbol (and is the only way to do so AFAIK). But you can perfectly use it in an otherwise standard quoted expression.  
Your original solution could therefore be reduced to something like:

```julia
julia> macro mymacro(ex)
           name, idx = ex.args
           return :([[$(QuoteNode(name))], $(idx) ])
       end
@mymacro (macro with 1 method)

julia> @macroexpand @mymacro mysym[15]
:([[:mysym], 15])

```

which I don’t find too unintuitive (once you know about `QuoteNode`)

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 22, 2021, 8:28pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/11 "2021-11-22T20:28:40Z")

</div>

Thanks! That’s exactly it.

> [@ffevotte](#):
>
> I would advise you to try and avoid having to use macros in this case.

Since I already mentioned the real use case of it:

> [@filchristou](#):
>
> The reason is using it to build a macro for evaluating JuMP variables.  
> e.g.
> 
> ```julia
> julia> @macroexpand @val myvar[(14,53)]
> :((model[:myvar])[(14,53)] |> OptNetILPs.value)
> 
> ```

what would you suggest for this situation if not a macro like the one you provided ?  
i.e.

```julia
macro val(ex)
    name, idx = ex.args
    :(model[$(QuoteNode(name))][$(idx)] |> value)
end

```

> [@ffevotte](#):
>
> which I don’t find too unintuitive

Well, certainly more intuitive than this: xD

> [@filchristou](#):
>
> As said, I did implemented it using expressions:
> 
> ```julia
> "evaluate indexed variable for JuMP model `model`"
> macro val(ex::Expr)
> Expr(:call, :|>, Expr(:ref, Expr(:ref, esc(:model), QuoteNode(ex.args[1])), ex.args[2]), :value)
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [November 22, 2021, 9:04pm UTC](https://discourse.julialang.org/t/constructing-expressions-with-local-macro-variables-and-symbols/71906/12 "2021-11-22T21:04:25Z")

</div>

> [@filchristou](#):
>
> what would you suggest for this situation

If this is something useful to JuMP users, it could be proposed upstream, so that the `@val` macro lives alongside other JuMP macros.

  

I haven’t thought about it much, but in this specific situation, maybe you could (ab)use `getproperty` in order to have a syntax like `val.myvar` instead of `@val myvar`. A sketch of the implementation could look like:

```julia
struct Value
    model
end

Base.getproperty(v::Value, sym::Symbol) = v.model[sym]

v = Value(model)
v.myvar[(14,53)] # equivalent to model[:myvar][(14, 53)]

```
