A youtuber leddoo posed an interesting “bug” (in some other language). It’s hard to explain in words but it has to do with whether a value is set before or after a subsequent block executes. Commenters actually were not unanimous on whether it should be 3 or 4; leddoo opined that it should be 3.
I adapted a code example to illustrate this behavior in Julia (v1.8). Interestingly, it depends on whether the variable is global or local, and it does not matter if the begin block is changed to a let block. Anyone know how to explain or justify this discrepancy?
julia> a = 1; (a, a + begin global a+=1 end, a) # reassign first
(2, 4, 2)
julia> a = 1; (a, a + let; global a+=1 end, a)
(2, 4, 2)
julia> let a = 1; (a, a + begin a+=1 end, a) end # reassign in order
(1, 3, 2)
julia> let a = 1; (a, a + let; a+=1 end, a) end
(1, 3, 2)
The global a
behavior can be done with a function reassigning a global variable, which seems like a more common if still rare problem to run into.
julia> function aplus() global a+=1 end
aplus (generic function with 1 method)
julia> a = 1; (a, a + aplus(), a)
(2, 4, 2)
You can get around the global a
references being evaluated last by doing some operation that returns a value equal to a
:
julia> a = 1; (a+0, (a+0) + begin global a+=1 end, a+0)
(1, 3, 2)
julia> a = 1; (a+0, a+0 + begin global a+=1 end, a+0)
(1, 4, 2)
The 2nd one slips to a (1, 2+2, 2)
because the middle expression calls +(a, 0, begin global a+=1 end)
. So to replicate the local a
behavior, you’d have to be pretty careful to make sure there’s no global a
at the same or higher level in nested function calls as the reassignments.
This seems important enough to point out in the OP. Dan found that a typed global behaves like a local on v1.9, but it still behaves like an untyped global on v1.8:
julia> a::Int = 1; (a, a + begin global a+=1 end, a) # v1.8
(2, 4, 2)
-------julia upgrade---------
julia> a::Int = 1; (a, a + begin global a+=1 end, a) # v1.9
(1, 3, 2)