Calling Threads.@threads in a macro definition

it’s a hygiene problem i think. is there a way to escape i? claude suggests i rewrite it to use @spawn, which i think would work, but i figure there must be a way to use @threads properly, no?

julia> macro foo()
         quote
           Threads.@threads for i=1:3
             println(i)
           end
         end
       end
@foo (macro with 1 method)

julia> @foo
ERROR: TaskFailedException

    nested task error: Global Main.i does not exist and cannot be assigned. Declare it using `global` before attempting assignment.
    Stacktrace:
     [1] (::var"#431#threadsfor_fun#2"{var"#431#threadsfor_fun#1#3"{UnitRange{Int64}}})(tid::Int64; onethread::Bool)
       @ Main ./threadingconstructs.jl:252
     [2] #431#threadsfor_fun
       @ ./threadingconstructs.jl:220 [inlined]
     [3] (::Base.Threads.var"#1#2"{var"#431#threadsfor_fun#2"{var"#431#threadsfor_fun#1#3"{UnitRange{Int64}}}, Int64})()
       @ Base.Threads ./threadingconstructs.jl:154
Stacktrace:
 [1] threading_run(fun::var"#431#threadsfor_fun#2"{var"#431#threadsfor_fun#1#3"{UnitRange{Int64}}}, static::Bool)
   @ Base.Threads ./threadingconstructs.jl:173
 [2] macro expansion
   @ ./threadingconstructs.jl:190 [inlined]
 [3] macro expansion
   @ ./REPL[1]:3 [inlined]
 [4] top-level scope
   @ ./REPL[3]:1

julia> Threads.@threads for i=1:3
         println(i)
       end
1
2
3

julia> macro foo()
         quote
           Threads.@threads for i=1:3
             println(i)
           end
         end |> esc
       end
@foo (macro with 1 method)

julia> @foo
1
2
3
1 Like

Except that this disables hygiene everywhere

julia> let
           println(i) = @show i
           a:b = reverse(UnitRange(a, b))
           @foo()
       end
i = 3
i = 2
i = 1

Probably better to only opt-out for the variable in question:

macro foo()
    i = esc(:i)
    quote
        Threads.@threads for $i=1:3
            println($i)
        end
    end
end
1 Like