Variables assigned in a loop block scope are different across iterations while if
statements don’t introduce new local scope at all, but what’s the variable scoping behavior for @label
-@goto
jumps? Initially I’d assume they just jump in and out of scopes created by other blocks, like in this example of 2 closures capturing 1 variable we assign twice by jump:
julia> function foo()
# 1 (steps for following control flow)
closures = []
count = 0
# 2, 4
@label assignx
@show x = rand()
if count == 1 @goto next end
# 3
push!(closures, () -> x)
count += 1
@goto assignx
# 5
@label next
push!(closures, () -> x)
closures
end
foo (generic function with 1 method)
julia> result = foo(); dump.(result);
x = rand() = 0.7004247485201015
x = rand() = 0.8141380475376465
#87 (function of type var"#87#89")
x: Core.Box
contents: Float64 0.8141380475376465
#88 (function of type var"#88#90")
x: Core.Box
contents: Float64 0.8141380475376465
julia> result[1].x === result[2].x # same boxed, captured variable
true
But when I rearrange the jump to resemble a while loop, it appears to make separate local variables as if it’s a loop block scope, in other words making an assignment after a jump created a separate captured variable. On the other hand, this variable isn’t isolated to the “loop” body:
julia> function bar()
# 1
closures = []
count = 0
# 2, 3
@label assignx
@show x = rand()
push!(closures, () -> x)
count += 1
if count == 1 @goto assignx end
# 4
closures, x
end
bar (generic function with 1 method)
julia> result = bar(); dump.(result);
x = rand() = 0.1924894128912077
x = rand() = 0.6303097583847382
Array{Any}((2,))
1: #27 (function of type var"#27#28"{Float64})
x: Float64 0.1924894128912077
2: #27 (function of type var"#27#28"{Float64})
x: Float64 0.6303097583847382
Float64 0.6303097583847382
Not sure if it matters, but this exercise was an offshoot of finding out that @label
(even with no @goto
) causes boxing of captured variables even in the absence of reassignments. All ran in v1.11.5.