# Calling Threads.@threads in a macro definition

**URL:** https://discourse.julialang.org/t/calling-threads-threads-in-a-macro-definition/132058
**Category:** General Usage
**Tags:** question
**Created:** [September 2, 2025, 5:25pm UTC](https://discourse.julialang.org/t/calling-threads-threads-in-a-macro-definition/132058 "2025-09-02T17:25:57Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![bjarthur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarthur/32/9638_2.png) [@bjarthur](https://discourse.julialang.org/u/bjarthur)
#### Post date: [September 2, 2025, 5:25pm UTC](https://discourse.julialang.org/t/calling-threads-threads-in-a-macro-definition/132058/1 "2025-09-02T17:25:57Z")

</div>

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-auto
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

```

---

<div class="post-metadata">

### Author: ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)
#### Post date: [September 2, 2025, 5:27pm UTC](https://discourse.julialang.org/t/calling-threads-threads-in-a-macro-definition/132058/2 "2025-09-02T17:27:52Z")

</div>

```julia-auto
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

```

> **[Metaprogramming · The Julia Language](https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene)**
>
> Documentation for The Julia Language.

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [September 2, 2025, 6:06pm UTC](https://discourse.julialang.org/t/calling-threads-threads-in-a-macro-definition/132058/3 "2025-09-02T18:06:39Z")

</div>

Except that this disables hygiene everywhere

```julia-repl
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:

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

```
