Broadcasting in macros

What is wrong with this macro:

julia> macro lessthanthree(vec)
       return :($vec .< 3)
       end
@lessthanthree (macro with 1 method)

julia> @lessthanthree 1:6
ERROR: UndefVarError: .< not defined
Stacktrace:
 [1] top-level scope at none:0

The following works:

julia> vec = 1:6
1:6

julia> eval(:($vec .< 3))
6-element BitArray{1}:
  true
  true
 false
 false
 false
 false

try returning esc(:($vec .< 3))

Julia macros are “hygenic” and can’t see values from the scope where they are invocked unless you use esc.

1 Like

This looks like a bug to me. It doesn’t happen on 1.2-rc1, but does on 1.1, although dump(@macroexpand @lessthanthree 1:6) looks identical. As ninjaaron says, an overall esc does seem to avoid it.

This is an error on both 1.1 and 1.2:

julia> @code_lowered 1:6 .< 3
ERROR: UndefVarError: .< not defined

On 0.6.4 you get this warning, and similar on 0.7:

julia> @lessthanthree 1:6
WARNING: .< is no longer a function object; use broadcast(<, ...) instead
1 Like

Thanks, using esc made the macro work for me as well and so does returning :(broadcast(<, $vec, 3)).

I have read the section about hygiene in the manual and I read it again and I still think I only half get it. Just for my own understanding, assuming it is not a bug, what is it about lessthanthree which might be non-hygienic? Overload of . or <?

Nah, it’s probably a bug. .< Should be accessible in the macro.

On the other hand, that $vec should be escaped anyway, because otherwise it’s not going to work if you try to pass the macro a variable in another module.