Personally, I appreciate @sadish-d for pointing out their opinions on Julia’s variable scope and declaration rules, as I think it’s nice to have people new to Julia provide fresh perspectives on certain “quirky” features of the language that frequent users might have taken for granted for so long.
Regarding this issue, I think the cause has more to do with the declaration of variables happening in compile time rather than runtime, which is before the if
statement or return
actually affects the evaluation of the program.
One thing that I found weird (and if someone can explain a good reason for that, I would be very thankful) is that to introduce a local variable, you don’t have to declare it location-wise before where it’s operated on (e.g., assignment, access):
julia> function foo1(x)
let
x=2
@show x
local x
end
x
end
foo1 (generic function with 1 method)
julia> let y=3
foo1(y)
end
x = 2
3
Even though the assignment of local x
does not appear before x=2
, it still shadows the outside x
(the input argument of foo1
) and makes x=2
only take effects inside the let
block. For comparison, this is the code and result without local x
:
julia> function foo1_2(x)
let
x=2
@show x
end
x
end
foo1_2 (generic function with 1 method)
julia> let y=3
foo1_2(y)
end
x = 2
2
It seems that the declaration of x
happens “before” the runtime evaluation (when the compiler does not know the value of the variables). In other words, the declaration of local variables is part of the static structure of their parent expression, regardless of all the evaluations (and even their orders) within it during the runtime. Another example more similar to OP’s example is:
julia> function foo2(x)
let
if false
local x
end
x=2
@show x
end
x
end
foo2 (generic function with 1 method)
julia> let y=3
foo2(y)
end
x = 2
3
Even though
if false
local x
end
wasn’t executed during the runtime,local x
successfully shadowed the input argument x
.