# Creating a variable inside a macro with specified name

**URL:** <https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187>\
**Category:** Optimization (Mathematical)\
**Tags:** jump, macros, macro-hygiene\
**Created:** [July 28, 2023, 8:34am UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187 "2023-07-28T08:34:48Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![shawn\_T](https://avatars.discourse-cdn.com/v4/letter/s/858c86/32.png) [@shawn\_T](https://discourse.julialang.org/u/shawn_T)\
**Post date:** [July 28, 2023, 8:34am UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/1 "2023-07-28T08:34:48Z")

</div>

Hi all,

I am trying to create a variable inside a Julia macro, then return the variable to the REPL, the variable should also have the name I specified from the macro input argument. I have two tests, the first test function below seems working:

```julia
macro my_test(args)

    var_call = add_variable(args)

    return esc( quote $args = $var_call end)
end

function add_variable(name)
    d = PhaseIndex(1)

    var_ref = generic_dy_ref(d,2)

    return var_ref
end

struct PhaseIndex
    p::Int64
end

struct generic_dy_ref
    phase::PhaseIndex
    index::Int64
end

```

It is able to generate a variable in the REPL with the same name as the input argument.

```julia
julia> @my_test(x)
generic_dy_ref(PhaseIndex(1), 2)

julia> x
generic_dy_ref(PhaseIndex(1), 2)

```

In my own macro I require a function call which is enclosed by :(), however, adding :() seems to create error at the return line, here is the modified test macro and the returning error, it seems that the “var\_call” cannot be evaluated in this way?

```julia
macro my_test(args)
    arg = esc(args)

    var_call = :(add_variable($arg))
   
    return esc( quote $args = $var_call end)
end

```

```julia
julia> @my_test(s)
ERROR: syntax: invalid syntax (escape (outerref s)) 
Stacktrace:
 [1] top-level scope

```

But I do need the :() otherwise my own macro will not work, is there any way to get it working?  
@odow I asked you about this on SO yesterday.

Thank you for your time.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [July 28, 2023, 10:38am UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/2 "2023-07-28T10:38:23Z")

</div>

You’re double escaping. You have `esc(args)` and at the end `esc` again. That’s one of the difficulties of macro hygiene in Julia that this is not allowed.

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [July 28, 2023, 10:38am UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/3 "2023-07-28T10:38:49Z")

</div>

The problem in this case is that you are escaping your variable twice in the returned expression.

It is very convenient to use the `@macroexpand` macro to verify what is the output of your macros to spot errors if something doesn’t work as intended.

In your case, using `@macroexpand` you would see:

```julia
julia> @macroexpand @my_test(s)
quote
    #= REPL[8]:6 =#
    s = add_variable($(Expr(:escape, :s)))
end

```

which shows that there is something weird on the arguments of `add_variable`.

If you remove your first line in the macro definition, everything should work as expected

```julia
julia> macro my_test(args)
           var_call = :(add_variable($args))
           return esc( quote $args = $var_call end)
       end

julia> @macroexpand @my_test(s)
quote
    #= REPL[10]:5 =#
    s = add_variable(s)
end

```

---

<div class="post-metadata">

**Author:** ![shawn\_T](https://avatars.discourse-cdn.com/v4/letter/s/858c86/32.png) [@shawn\_T](https://discourse.julialang.org/u/shawn_T)\
**Post date:** [July 28, 2023, 1:07pm UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/4 "2023-07-28T13:07:56Z")

</div>

Thank you,

But what if I have to use esc() for one of the function arguments? My “model” here is a structure type, I have to use esc to ensure hygiene.

I guess I have to adjust the “ref” in the return line to exclude the escaped part of the expression?

```julia
macro differential(model,args...)

    ref = :(add_variable($(esc(model)),$(args)))
    ...

return esc( quote $args = $ref end)

```

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [July 28, 2023, 1:47pm UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/5 "2023-07-28T13:47:36Z")

</div>

I think it might be useful to have a read at this other discourse post:

> [@Escaping in a macro](https://discourse.julialang.org/t/escaping-in-a-macro/14543):
>
> In the documentation of Julia v1.0 there is almost nothing about escaping in a macro. I tried a simple debug function, which can be inserted at critical points of a function. It should print an expression or variable name, and its current value. I defined a macro in a module, but I get weird messages (b = c =) at loading the module, and within a function only the last value of several calls to the macro is actually shown in REPL. If I type in REPL @db(1+2) or a = falses(2); @db(a) I get the de…

to have a better understanding of escaping in macros.

As written there, each input generally has to be escaped **once and exactly once**.

So for your added example, you also just avoid escaping `model` (like done for `args` in the previous answer) inside this line:

```julia
ref = :(add_variable($(esc(model)),$(args)))

```

as it will anyhow be escaped once you escape the quote returned by the macro.

---

<div class="post-metadata">

**Author:** ![shawn\_T](https://avatars.discourse-cdn.com/v4/letter/s/858c86/32.png) [@shawn\_T](https://discourse.julialang.org/u/shawn_T)\
**Post date:** [July 28, 2023, 4:05pm UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/6 "2023-07-28T16:05:33Z")

</div>

Thank you very much,

A final question, as I was starting to use macroexpand to check my code, how did you tell (like the code you showed above) that there should be error from something like $(Expr(:escape, :s)) as the function argument? From my understanding, macroexpand is just showing the expression to be evaluated from macro return.

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [July 28, 2023, 4:08pm UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/7 "2023-07-28T16:08:53Z")

</div>

You could look at JuMP for inspiration since its macros seem to do this (`@variable` in particular).

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [July 28, 2023, 5:44pm UTC](https://discourse.julialang.org/t/creating-a-variable-inside-a-macro-with-specified-name/102187/8 "2023-07-28T17:44:50Z")

</div>

Except for the `begin end` that becomes `quote end` the output of `@macroexpand` should look like the code you’d write manually if you didn’t have the macro (for the most part, there are also linenumbernodes that you can ignore).

So whenever you see an `Expr` in the output of the `@macroexpand`, unless you are building macros to create expressions it means that something went wrong.

The `$(Expr(:escape, _something_))` is quite a common pattern when starting to make macros as hygiene and escaping is not so straightforward so you are bound to find them a lot in the various macro definition attempts (at least I did and still do when creating macros). But you soon learn that it’s not supposed to be in the output of `@macroexpand`, and what it’s causing that (too many `esc` on a variable).
