# How to make a macro modify struct member?

**URL:** <https://discourse.julialang.org/t/how-to-make-a-macro-modify-struct-member/68991>\
**Category:** General Usage\
**Tags:** macros, struct\
**Created:** [September 30, 2021, 11:54am UTC](https://discourse.julialang.org/t/how-to-make-a-macro-modify-struct-member/68991 "2021-09-30T11:54:41Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![droodman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/droodman/32/26652_2.png) [@droodman](https://discourse.julialang.org/u/droodman)\
**Post date:** [September 30, 2021, 11:54am UTC](https://discourse.julialang.org/t/how-to-make-a-macro-modify-struct-member/68991/1 "2021-09-30T11:54:41Z")

</div>

I am trying to write a macro that may generate an assignment statement to modify one of its arguments (more precisely, modify the object the argument binds to). That argument will be a member of a mutable struct; which member will vary from call to call.

It seems that when I pass a struct member reference to a macro, Julia’s macro expansion assumes the argument is a global within the current module, not local to the scope of the calling function, which leads to a crash. What am I doing wrong?

Example:

```julia
mutable struct S x end

macro m(arg)
    :( $arg = 1 )
end

function f()
    @show @macroexpand @m(s)
    @show @macroexpand @m(s.x)

    s = S(1)
    @m(s.x)
end

f()

```

When I run this, I get

```julia
#= Untitled-1:8 =# @macroexpand(#= Untitled-1:8 =# @m(s)) = :(var"#18#s" = 1)
#= Untitled-1:9 =# @macroexpand(#= Untitled-1:9 =# @m(s.x)) = :((Main.s).x = 1)
ERROR: LoadError: UndefVarError: s not defined
Stacktrace:
 [1] f()
   @ Main .\Untitled-1:12
 [2] top-level scope
   @ Untitled-1:15
in expression starting at Untitled-1:15

```

The first @macroexpand output line looks like I would want it to look: it assigns via a temporary alias with no scope qualifications. The second instead refers directly to Main.s, which does not exist. I just want it to refer to s, the calling function’s local variable.

Background: my real purpose is to cleanly and efficiently implement what is in spirit a “!” function that may in some cases produce output exactly equal to one of its inputs. In those cases, I do not want to copy the input matrix into the provided output matrix, but rather change the binding of the caller’s name for the output matrix to the input matrix. A macro seems like the Julianic way to do this, but maybe not?

---

<div class="post-metadata">

**Author:** ![sostock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sostock/32/5546_2.png) [@sostock](https://discourse.julialang.org/u/sostock)\
**Post date:** [September 30, 2021, 1:49pm UTC](https://discourse.julialang.org/t/how-to-make-a-macro-modify-struct-member/68991/2 "2021-09-30T13:49:54Z")

</div>

To make `s` refer to the local variable, you have to escape `arg`:

```julia
macro m(arg)
    :($(esc(arg)) = 1)
end

```

```julia
julia> f()
#= REPL[6]:2 =# @macroexpand(#= REPL[6]:2 =# @m(s)) = :(s = 1)
#= REPL[6]:3 =# @macroexpand(#= REPL[6]:3 =# @m(s.x)) = :(s.x = 1)
1

```

However, this also changes the behavior in the first case `@m(s)`, even though you want the old behavior in that case (if I understand you correctly). To achieve that, you would have to return different expressions (with or without `esc`) depending on whether your argument is a single variable (a `Symbol`) or not.
