# Macro: escaping, interpolation, scope etc

**URL:** <https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 20, 2019, 4:52pm UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408 "2019-05-20T16:52:55Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![samo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samo/32/35398_2.png) [@samo](https://discourse.julialang.org/u/samo)\
**Post date:** [May 20, 2019, 4:52pm UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/1 "2019-05-20T16:52:55Z")

</div>

I would like to achieve something along the following lines: when I write `@all(A)`, it should replace it with `A[ix,iy,iz]` in the caller’s scope (`ix`, `iy` and `iz` are defined in the caller’s scope).

So, I wrote the following macro:

```julia
macro all(A) :( esc($A[ix,iy,iz]) ) end

```

However, it does not work as wished:

```julia
$>julia

julia> macro all(A) :( esc($A[ix ,iy ,iz]) ) end

@all (macro with 1 method)

julia> B = ones(2, 3, 1)
2×3×1 Array{Float64,3}:
[:, :, 1] =
 1.0 1.0 1.0
 1.0 1.0 1.0

julia> ix = 2;

julia> iy = 1;

julia> iz = 1;

julia> @macroexpand @all(B)
:((Main.esc)((Main.B)[Main.ix, Main.iy, Main.iz]))

julia> @all(B)
:($(Expr(:escape, 1.0)))

julia> eval(@all(B))
ERROR: syntax: invalid syntax (escape #<julia: 1>)
Stacktrace:
 [1] eval at ./boot.jl:319 [inlined]
 [2] eval(::Expr) at ./client.jl:393
 [3] top-level scope at none:0

```

And if I try to call the macro from within a function, I get:

```julia
julia> function f()
           C = ones(5,5,5);
           ix = 1;
           iy = 2;
           iz = 1;
           println(@macroexpand @all(C))
           println(@all(C))
       end
f (generic function with 1 method)

julia> f()
(Main.esc)((Main.C)[Main.ix, Main.iy, Main.iz])
ERROR: UndefVarError: C not defined
Stacktrace:
 [1] f() at ./none:7
 [2] top-level scope at none:0

```

**Questions**

1. When called within the function `f()`, why does the macro expand to an expression containing `Main.C` and not `f.C` (and `Main.ix` and not `f.ix` etc)?
2. How can I fix this macro to achieve what I described at the beginning?

Thanks!

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [May 20, 2019, 6:07pm UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/2 "2019-05-20T18:07:46Z")

</div>

(1) Macros are evaluated before the functions that contain them. You see `Main._` because that is the context in which the macro is evaluated.

(2) I’d start with `macro all(A) :( $(esc(A))[ix,iy,iz] ) end`.  
or `macro all(A, ix, iy, iz) `

---

<div class="post-metadata">

**Author:** ![samo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samo/32/35398_2.png) [@samo](https://discourse.julialang.org/u/samo)\
**Post date:** [May 21, 2019, 8:17am UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/3 "2019-05-21T08:17:45Z")

</div>

@thanks @JeffreySarnoff! The modification that you suggested makes the macro work if called from `Main`:

```julia
$>julia

julia> macro all(A) :( $(esc(A))[ix,iy,iz] ) end
@all (macro with 1 method)

julia> B = ones(2, 3, 1)
2×3×1 Array{Float64,3}:
[:, :, 1] =
 1.0 1.0 1.0
 1.0 1.0 1.0

julia> ix = 2;

julia> iy = 1;

julia> iz = 1;

julia> @all(B)
1.0

julia> @macroexpand @all(B)
:(B[Main.ix, Main.iy, Main.iz])

```

What do you suggest to make it work when called from a function. The current macro leads to the following error:

```julia
$>julia

julia> macro all(A) :( $(esc(A))[ix,iy,iz] ) end
@all (macro with 1 method)

julia> B = ones(2, 3, 1)
2×3×1 Array{Float64,3}:
[:, :, 1] =
 1.0 1.0 1.0
 1.0 1.0 1.0

julia> function f()
           C = ones(5,5,5);
           ix = 1;
           iy = 2;
           iz = 1;
           println(@macroexpand @all(C))
           println(@all(C))
       end
f (generic function with 1 method)

julia> f()
C[Main.ix, Main.iy, Main.iz]
ERROR: UndefVarError: ix not defined
Stacktrace:
 [1] f() at ./none:15
 [2] top-level scope at none:0

```

And escaping `ix`,`iy` and `iz` does not solve it:

```julia
julia> macro all(A) :( $(esc(A))[esc(ix),esc(iy),esc(iz)] ) end
@all (macro with 1 method)

julia> B = ones(2, 3, 1)
2×3×1 Array{Float64,3}:
[:, :, 1] =
 1.0 1.0 1.0
 1.0 1.0 1.0

julia> function f()
           C = ones(5,5,5);
           ix = 1;
           iy = 2;
           iz = 1;
           println(@macroexpand @all(C))
           println(@all(C))
       end
f (generic function with 1 method)

julia> f()
C[(Main.esc)(Main.ix), (Main.esc)(Main.iy), (Main.esc)(Main.iz)]
ERROR: UndefVarError: ix not defined
Stacktrace:
 [1] f() at ./none:15
 [2] top-level scope at none:0

```

Note: a macro `all(A, ix, iy, iz)` is not an option as one of the aims of the macro is not to have to specify `ix`, `iy` and `iz`.

Thanks!

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 21, 2019, 9:02am UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/4 "2019-05-21T09:02:59Z")

</div>

```julia
julia> macro all(A) :( $(esc(A))[$(esc(:ix)), $(esc(:iy)), $(esc(:iz))] ) end
@all (macro with 1 method)

julia> B = ones(2, 3, 1)
2×3×1 Array{Float64,3}:
[:, :, 1] =
 1.0 1.0 1.0
 1.0 1.0 1.0

julia> function f()
           C = ones(5,5,5);
           ix = 1;
           iy = 2;
           iz = 1;
           println(@macroexpand @all(C))
           println(@all(C))
       end
f (generic function with 1 method)

julia> f()
C[ix, iy, iz]
1.0

```

---

<div class="post-metadata">

**Author:** ![samo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samo/32/35398_2.png) [@samo](https://discourse.julialang.org/u/samo)\
**Post date:** [May 21, 2019, 9:52am UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/5 "2019-05-21T09:52:47Z")

</div>

Great, thanks @kristoffer.carlsson! It works. However, it has become really ugly to read. How can I separate the majority of the escape/scope/interpolation story from the essence of the macro (the expression `A[ix,iy,iz]`)? The ideal case would be something like any of the following (which do not work of course):

```julia
macro _all(A,ix,iy,iz) :( A[ix,iy,iz] ) end
macro all(A) @_all($(esc(A)),$(esc(:ix)),$(esc(:iy)),$(esc(:iz))) end

```

or

```julia
macro all(A)
    A = $(esc(A));
    ix = $(esc(:ix));
    iy = $(esc(:iy));
    iz = $(esc(:iz));
    return :( A[ix,iy,iz] )
end

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 21, 2019, 12:29pm UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/6 "2019-05-21T12:29:05Z")

</div>

```julia
macro all(A)
    A = esc(A)
    ix = esc(:ix)
    iy = esc(:iy)
    iz = esc(:iz)
    return :( $A[$ix, $iy, $iz] )
end

```

or

```julia
macro all(A)
    A, ix, iy, iz = esc.((A, :ix, :iy, :iz))
    return :( $A[$ix, $iy, $iz] )
end

```

---

<div class="post-metadata">

**Author:** ![samo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samo/32/35398_2.png) [@samo](https://discourse.julialang.org/u/samo)\
**Post date:** [May 21, 2019, 1:20pm UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/7 "2019-05-21T13:20:26Z")

</div>

Thanks @kristoffer.carlsson! I love the second one! It is so concise it can even go on one line 🙂

```julia
macro all(A) A,ix,iy,iz = esc.((A,:ix,:iy,:iz)); :($A[$ix,$iy,$iz]) end

```

---

<div class="post-metadata">

**Author:** ![samo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samo/32/35398_2.png) [@samo](https://discourse.julialang.org/u/samo)\
**Post date:** [May 24, 2019, 10:02am UTC](https://discourse.julialang.org/t/macro-escaping-interpolation-scope-etc/24408/8 "2019-05-24T10:02:26Z")

</div>

@kristoffer.carlsson and @JeffreySarnoff, I just found a shorter solution:

```julia
macro all(A) esc(:($A[ix,iy,iz])) end

```

Here is its usage within the example from above:

```julia
$>julia

julia> macro all(A) esc(:($A[ix,iy,iz])) end
@all (macro with 1 method)

julia> function f()
           C = ones(5,5,5);
           ix = 1;
           iy = 2;
           iz = 1;
           println(@macroexpand @all(C))
           println(@all(C))
       end
f (generic function with 1 method)

julia> f()
C[ix, iy, iz]
1.0

```

**So to summarize, we have the two following solutions in this topic:**

_Solution 1:_

```julia
macro all(A) A,ix,iy,iz = esc.((A,:ix,:iy,:iz)); :($A[$ix,$iy,$iz]) end

```

_Solution 2:_

```julia
macro all(A) esc(:($A[ix,iy,iz])) end

```

Is there any reason to prefer one solution over the other (besides the conciseness which speaks clearly for solution 2)?  
Could you explain what is the difference, i.e. what exactly happens when these macros are evaluated?  
Thanks!
