Why does this code snippet print 2 instead of 1?
anon = Array{Any}(undef, 2)
for i = 1:2
anon[i] = ()-> println(i)
i += 1
end
anon[1]()
Why does this code snippet print 2 instead of 1?
anon = Array{Any}(undef, 2)
for i = 1:2
anon[i] = ()-> println(i)
i += 1
end
anon[1]()
This is just how closures work. The closure () -> println(i)
closes over the binding i
, not just its current value, so it can see changes to that binding. Here’s another example:
julia> function outer()
i = 1
inner = () -> println(i)
i = 2
return inner
end
outer (generic function with 1 method)
julia> f = outer()
#7 (generic function with 1 method)
julia> f()
2
Note that this can be confusing because a for-loop introduces a new local variable i
at each iteration, so if you do:
julia> fs = []
Any[]
julia> for i in 1:2
push!(fs, () -> i)
end
julia> fs[1]()
1
julia> fs[2]()
2
then fs[1]
has captured the variable i
introduced by the first iteration of the loop, while fs[2]
has captured the variable i
introduced by the second iteration of the loop.
If the i
were the same binding in each iteration of the loop, then you’d get 2
both times due to the for
loop incrementing i
. In fact, Python does that, which can be very confusing when you switch between Python and Julia:
# Python
>>> fs = []
>>> for i in range(1, 3):
... fs.append(lambda: i)
...
>>> fs[0]()
2
>>> fs[1]()
2