It’s because the remote process has to know where to put the result. There’s a module wide sync variable for distributed operations, according to the source of @spawnat and what the macro expands to:
[sukera@tempman ~]$ julia -q -p 2
julia> using Distributed
julia> module Test
using Distributed
function test()
t = @spawnat :2 1==1
@show fetch(t)
end
end
Main.Test
julia> using .Test
julia> @code_lowered Test.test()
CodeInfo(
1 ─ Core.NewvarNode(:(value))
│ Core.NewvarNode(:(t))
│ #1 = %new(Main.Test.:(var"#1#2"))
│ %4 = #1
│ ref = Distributed.spawnat($(QuoteNode(2)), %4)
└── goto #3 if not false
2 ─ Distributed.put!(Main.Test.:(var"##sync#48"), ref)
3 ┄ t = ref
│ %9 = Main.Test.fetch(t)
│ value = %9
│ %11 = Base.repr(%9)
│ Base.println("fetch(t) = ", %11)
└── return value
)
Distributed creates a Future, passes that to the external process to place the result into and then assigns that Future to t. I’m not sure if that requires knowing the Test module though, may be a bug.
EDIT: thinking about this some more, it does require knowing about the containing module, because there may be more than one module referencing that variable. I guess it could be gensymd, but then how would that be communicated to the remote process?