# Macro behaves differently than manually running the output of macroexpand

**URL:** <https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727>\
**Category:** General Usage\
**Created:** [July 29, 2018, 11:41pm UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727 "2018-07-29T23:41:43Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [July 29, 2018, 11:41pm UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/1 "2018-07-29T23:41:43Z")

</div>

I’m trying to write a macro and found a problem that I fail to debug, since `macroexpand` gives code that runs just fine.  
MWE (on Julia 0.6.3):  
after defining

```julia
function _b(iter_vars, ranges)
  iter_exprs = [:($(esc(v)) = $(esc(r))) for (v,r) in zip(iter_vars,ranges)]
  var_array_ex = Expr(:vect, (esc(v) for v in iter_vars)...)
  quote
      $(Expr(:comprehension, Expr(:generator,
                          quote
                            $var_array_ex .+ 1
                          end,
                          iter_exprs...
                       )))
  end
end

macro _b(iters...)
  iter_vars = [e.args[1] for e in iters]
  ranges = [e.args[2] for e in iters]
  _b(iter_vars, ranges)
end

```

running the macro `_b` gives a warning

```julia
julia> @_b( i=1:1, j=1:1 )
WARNING: .+ is no longer a function object; use broadcast(+, ...) instead
Stacktrace:
 [1] depwarn(::String, ::Symbol) at .\deprecated.jl:70
 [2] (::Base.##719#720)(::Array{Int64,1}, ::Int64) at .\deprecated.jl:355
 [3] macro expansion at .\REPL[9]:0 [inlined]
 [4] (::##7#8)(::Tuple{Int64,Int64}) at .\REPL[9]:7
 [5] collect(::Base.Generator{Base.Iterators.Prod2{UnitRange{Int64},UnitRange{Int64}},##7#8}) at .\array.jl:470
 [6] eval(::Module, ::Any) at .\boot.jl:235
 [7] eval_user_input(::Any, ::Base.REPL.REPLBackend) at .\REPL.jl:66
 [8] macro expansion at .\REPL.jl:97 [inlined]
 [9] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at .\event.jl:73
while loading no file, in expression starting on line 5
1×1 Array{Array{Int64,1},2}:
 [2, 2]

```

However, running the result of `macroexpand` “manually” yields no warning:

```julia
julia> @macroexpand @_b( i=1:1, j=1:1 )
quote # REPL[9], line 5:
    [begin # REPL[9], line 7:
        [i, j] .+ 1
    end for i = 1:1, j = 1:1]
end

julia> [begin
         [i,j] .+ 1
         end for i=1:1, j=1:1]
1×1 Array{Array{Int64,1},2}:
 [2, 2]

```

I can work around this by using a loop, but would like to understand what is happening here.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [July 30, 2018, 12:04am UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/2 "2018-07-30T00:04:23Z")

</div>

> [@yha](#):
>
> macro \_b(iters…) iter\_vars = [e.args[1] for e in iters] ranges = [e.args[2] for e in iters] \_b(iter\_vars, ranges) end

This macro is entirely ran at compile-time and does not output an expression. I think you meant:

```julia
macro _b(iters...)
  iter_vars = [e.args[1] for e in iters]
  ranges = [e.args[2] for e in iters]
  quote
    _b(iter_vars, ranges)
  end
end

```

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 30, 2018, 12:14am UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/3 "2018-07-30T00:14:10Z")

</div>

> [@ChrisRackauckas](#):
>
> \_b(iter\_vars, ranges)

Well, you would at least need to interpolate the two variables…

> [@ChrisRackauckas](#):
>
> I think you meant:

I don’t think so. `_b` operate on expressions.

I think (not easy for me to check right now) the warning won’t be raised unless the expression is evaluated (lowered at least) so `@macroexpand` won’t have any issue.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [July 30, 2018, 12:16am UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/4 "2018-07-30T00:16:49Z")

</div>

Oh that’s my bad. I didn’t see that the inner function was returning a quoted expression. Ignore my first comment.

---

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [July 30, 2018, 12:21am UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/5 "2018-07-30T00:21:04Z")

</div>

> [@yuyichao](#):
>
> I think (not easy for me to check right now) the warning won’t be raised unless the expression is evaluated (lowered at least) so `@macroexpand` won’t have any issue.

I’m not sure I understand what you mean. To clarify, the warning is not raised when copy-pasting and running the expression returned by `@macroexpand`. I expect this to be equivalent to running the macro, and also to `eval(@macroexpand ...)`, but both of these do show the warning.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [July 30, 2018, 12:26am UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/6 "2018-07-30T00:26:22Z")

</div>

It’s fixed if you follow the issue and do:

```julia
  quote
      $(Expr(:comprehension, Expr(:generator,
                          quote
                            broadcast(+,$var_array_ex,1)
                          end,
                          iter_exprs...
                       )))
  end

```

The issue is likely due to the fact that on v0.6 broadcast is implemented in the parser, see [More Dots: Syntactic Loop Fusion in Julia](https://julialang.org/blog/2017/01/moredots) for details. At parse time broadcasted expressions are changed to `broadcast(...)` calls in order to fuse, however that must not be happening inside of the quoted expression.

However, on v0.7 the implementation of broadcast changed to be done lazily through the type system as discussed in this blog: [Extensible broadcast fusion](https://julialang.org/blog/2018/05/extensible-broadcast-fusion) . When I check on v0.7 I also get the same warning, so there must be more to it.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 30, 2018, 1:25am UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/7 "2018-07-30T01:25:42Z")

</div>

> [@yha](#):
>
> I’m not sure I understand what you mean

I mean `macroexpand` the expression but not evaluate it. It only evaluate the macro body. The warning is raised in the step(s) in between macro expansion and evaluation which is why it’s not raised when you only do macro expansion. More about copy-paste below.

> [@ChrisRackauckas](#):
>
> on v0.6 broadcast is implemented in the parser,

> [@ChrisRackauckas](#):
>
> At parse time broadcasted expressions are changed to `broadcast(...)` calls in order to fuse, however that must not be happening inside of the quoted expression.

And no. It’s implemented in the frontend but not the parser (i.e. lowering not parsing).

> [@ChrisRackauckas](#):
>
> However, on v0.7 the implementation of broadcast changed to be done lazily

I don’t believe the dot to “broadcast” conversion has moved in 0.7 so it’s not surprising that the warning is still there. The only difference is the form of the “boardcast”.

> [@yha](#):
>
> when copy-pasting and running the expression returned by `@macroexpand` .

That actually shows you that the copy paste isn’t accurate, or more like the printing doesn’t give you full information:

```julia
julia> macro m(a, b)
           :($(esc(a)) .* $(esc(b)))
       end
@m (macro with 1 method)

julia> @macroexpand @m a b
:(a .* b)

julia> Meta.show_sexpr(@macroexpand @m a b)
(:call, :(Main..*), :a, :b)
julia> :(a .* b)
:(a .* b)

julia> Meta.show_sexpr(:(a .* b))
(:call, :.*, :a, :b)

```

This is a bug in macro hygiene. It should probably just keep `.*` intact since it’s not a name anymore. It’s very hard to do before the depwarn is removed though since that changes the semantics.

---

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [July 31, 2018, 3:10pm UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/8 "2018-07-31T15:10:09Z")

</div>

Wouldn’t that also be a bug in the printing of expressions, since `(:call, :(Main..*), :a, :b)` and `(:call, :.*, :a, :b)` are printed identically? Or is it unrealistic to expect the pretty-printing of expressions to be unambiguous?  
In the latter case, perhaps the documentation should stress the use of `Meta.show_sexpr` more. It’s briefly mentioned in the Metaprogramming section, but not as a something that provides more detailed information, and not in the context of `macroexpand`.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 31, 2018, 5:29pm UTC](https://discourse.julialang.org/t/macro-behaves-differently-than-manually-running-the-output-of-macroexpand/12727/9 "2018-07-31T17:29:15Z")

</div>

> [@yha](#):
>
> Wouldn’t that also be a bug in the printing of expressions, since `(:call, :(Main..*), :a, :b)` and `(:call, :.*, :a, :b)` are printed identically? Or is it unrealistic to expect the pretty-printing of expressions to be unambiguous?

It’s a trade off. It’ll be pretty bad if everything in the macro expansion looks like `M.:+(a, b)` instead of `a + b`…

> [@yuyichao](#):
>
> It should probably just keep `.*` intact

Actually that’s not correct. The `*` in `.*` should still need proper scope so the macro expander isn’t doing anything wrong and the proper fix is impossible without the removal of the deprecation.
