If a global variable is defined outside of a closure and only "conditionally defined" inside the closure an UndefVarError is thrown.
bla = 1
map([1]) do x
isdefined(:bla) || (bla=2)
println(bla)
end
ERROR: UndefVarError: bla not defined
in (::##1#2)(::Int64) at ./REPL[2]:6
in _collect(::Array{Int64,1}, ::Base.Generator{Array{Int64,1},##1#2}, ::Base.EltypeUnknown, ::Base.HasShape) at ./array.jl:379
in map(::Function, ::Array{Int64,1}) at ./abstractarray.jl:1803
Julia Version 0.6.0-pre.beta.401
Commit 96608db (2017-04-28 14:18 UTC)
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: Intel(R) Core(TM) i7-4600U CPU @ 2.10GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.9.1 (ORCJIT, haswell)
Note that the code does not what I intended it to do (overwrite bla), but its still incorrect behaviour I would say.
This is expected behavior.
bla is a local variable and not a global one in the function since it is assigned to in the function and not declared as global in the functionisdefined check for global variable.Ref https://docs.julialang.org/en/latest/devdocs/functions.html#Closures-1 (search closure) (the function does not capture any variable since it is directly under global scope)
https://docs.julialang.org/en/latest/manual/variables-and-scoping.html#Hard-Local-Scope-1 (search scoppe)
and then https://docs.julialang.org/en/latest/stdlib/base.html#Core.isdefined (search isdefined).
Why is that expected? If bla is not defined globally I might want it to define it locally and use that value. If it is defined globally however I want to use the global value. I know that after the map call bla will still be 1. Its certainly a corner case, but I don't see why this behaviour is expected.
It's expected and a good thing. If local variables bound to global variables by default, that would cause all sorts of havok; imagine if running norm = x^2 + y^2 in your function overwrote the global norm binding (to the function norm)! You can explicitly set a global variable locally by using the global keyword.
To be clear, this has nothing to do with the if condition. Assignments to variables in a function are never global by default.
I agree that local variables should not bound to globals for the reasons you mention. And as I said I don't expect bla=2 to modify the global bla, but I expect bla to be defined to 2 inside the anonymous function.
I don't agree that my case has nothing to do with the if. If one removes it and just writes bla=2 (i.e. condition is true) there is no error. If one removes it and additionally removes bla=2 there is also no error.
This is not a bug since it is intentional (and thoroughly documented). The merits of the design of scoping in the language would be better discussed on Discourse.
These two rules make the behavior easy to predict and rules out the behavior you want.
@tehrengruber: you may be intuitively expecting something like dynamic scoping, but that was found to be quite problematic in early Lisps despite being intuitive and fell out of favor long ago.
@yuyichao that was contrary to my expectations and @StefanKarpinski link explains nicely why its good that this does not work. Thanks for pointing this out so clearly. I should probably need to change my workflow into something like Gitter -> Discourse -> Issue...
Most helpful comment
These two rules make the behavior easy to predict and rules out the behavior you want.