I have been experimenting with the behavior of global variables in Julia.
I (perhaps incorrectly) believed the behavior was quite similar, if not exactly the same, as in Python.
Here’s some test code:
global x="x"
y="y"
function printtype()
println("typeof(x)=$(typeof(x))")
println("typeof(y)=$(typeof(y))")
end
function printxy()
println("printxy: x=$(x)")
println("printxy: y=$(y)")
end
function printxyglobal()
global x
global y
println("printxyglobal: x=$(x)")
println("printxyglobal: y=$(y)")
end
function changexy()
println("changexy: x=$(x)") # added later
if !@isdefined(x) # added later
println("x is not defined") # added later
println("x= $(x)") # added later
println(x) # added later
end # added later
x = x == "x" ? "xx" : "x"
y = y == "y" ? "yy" : "y"
println("end of changexy") # added later
end
# FYI
function changexy_original()
x = x == "x" ? "xx" : "x"
y = y == "y" ? "yy" : "y"
end
function changexyglobal()
global x
global y
x = x == "x" ? "xx" : "x"
y = y == "y" ? "yy" : "y"
end
function changexytypeglobal()
global x
global y
x = x == "x" ? 1 : "x"
y = y == "y" ? 2 : "y"
end
println("printtype:")
printtype()
println("printxy:")
printxy()
println("printxyglobal:")
printxyglobal()
println("changexy:")
changexy()
println("printxy:")
printxy()
println("printxyglobal:")
printxyglobal()
println("changexyglobal:")
changexyglobal()
println("printxy:")
printxy()
println("printxyglobal:")
printxyglobal()
println("changexytypeglobal:")
changexytypeglobal()
println("printxy:")
printxy()
println("printxyglobal:")
printxyglobal()
println("done")
Here is the output:
$ julia global.jl
printtype:
typeof(x)=String
typeof(y)=String
printxy:
printxy: x=x
printxy: y=y
printxyglobal:
printxyglobal: x=x
printxyglobal: y=y
changexy:
ERROR: LoadError: UndefVarError: `x` not defined in local scope
If it wasn’t already obvious from running this code, what I find surprising is this:
printxy is able to readx and y without global (this is what I expect)
printxyglobal behaves the same as printxy (again, exactly as I expect)
changexycannot read x! This appears to be in conflict with the behavior seen in printxy
The final bullet point is really the surprise. The first two are expected behaviors.
Is anyone able to help me understand why this happens?
I’m assuming I haven’t made a dumb mistake her or otherwise doing something obviously wrong?
It’s because you assign to x in changexy, without declaring it as a global. The compiler sees the assignment and determines it is a local variable. However, at the point where it is read, it has not been defined yet. It’s just a local name which is not referring to anything yet. It’s like
julia> f() = (local x; println(x))
f (generic function with 1 method)
julia> f()
ERROR: UndefVarError: `x` not defined in local scope
The assignment in the function body treats the variable as a local variable by default. You need a global statement to override it. Python has the same rule:
>>> x = 1
>>> def foo():
... print("1: ", x)
... x = 2
... print("2: ", x)
...
>>> foo()
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
foo()
~~~^^
File "<python-input-1>", line 2, in foo
print("1: ", x)
^
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
>>> def foo():
... global x
... print("1: ", x)
... x = 2
... print("2: ", x)
...
>>> foo()
1: 1
2: 2
>>> x
2
…though it’s worth pointing out there are other differences in rules. One difference is Python errors if the statement isn’t ahead of all the working code. Julia’s global/local statements apply to the entire scope it’s written in, regardless of which line except the final returning line where global without assignment errors. It’s better to not expect Julia to work like Python despite the relative similarities among other languages.
For anyone reading this in future, the issue appears to be that the following line does not make much sense.
x = x == "x" ? "xx" : "x"
First, the value of x is compared against "x". We have to ask the question, which x, or “what is x?” Since x has not been assigned to in the function, the answer is obvious. This refers to the global x, which exists outside of the function.
Next, having evaluated x == "x" ? "xx" : "x", we can assign the result to x.
Again, we ask the question, to which x does this refer?
Since we are writing to a variable x and this variable has not been declared as global x at the beginning of our function, this x must be a new local variable x.
However, this statement conflicts with the previous statement where we concluded x was the global variable x.
julia> global x = "x"
"x"
julia> function f()
let x = x
x = x == "x" ? "xx" : "x"
println(x)
end
end
f (generic function with 1 method)
julia> f()
xx
julia> x
"x"
Perhaps I’m being too terse. You posted a summary regarding scoping that included a small inaccuracy. There have been threads here before because of confusion from the position- independent nature of global. My intention was not to encourage moving global later but rather to warn that a later global can introduce unexpected behavior, thus the quote. I did not mean any offense and I’m sorry you took it that way.
I quoted you to indicate my intention of the previous post was to provide more information and hopefully dispel confusion for your future readers (intentionally not quoting you again), and not that I was suggesting a late global as you had interpreted it. I’ve already offered you an apology.
I don’t think this was meant as a quote of @world-peace from another thread at all. This is a pretty standard expression that lots of people use on internet forums.
which is not the same sentence that @Jeff_Emanuel used.
On this Discourse, please assume good intentions from the people you interact with, unless they have explicitly proved you wrong. I can’t recall observing mockery on this site, and I have no doubt @Jeff_Emanuel was genuinely trying to help.
I don’t think it’s too far-fetched to interpret @Jeff_Emanuel 's
as slightly mocking, but equally it could be interpreted as tongue-in-cheek. The medium of text just doesn’t lend itself to these kind of nuances (unless you add emoticons or stuff like /s.).
Anyway, @Jeff_Emanuel clarified that there was no ill-intent and apologised, so let’s just leave it at that and move on.
@eldee perhaps you’re right. I might have over-interpreted the “elsewhere” here, thinking that it referred to another thread.
In any case, that’s exactly the problem: we should all spend less time interpreting what everyone’s intentions are, and more time solving each other’s problems
I think it’s reasonable that I should be unhappy about this.
From my point of view, it appears that there is a double standard being applied here. I do not know why.
Previously my account has been banned for the most minor of faux-pas, but in this case it seems that for some reason not known to me, a technicality is being used to enable someone to mock someone else on the forums.
If I had posted this, I am pretty sure I would get banned again.
Previous decisions by the moderation are not the subject here. We have already discussed those at length with you, both in public and in private. The same standards apply to everyone.
You are entitled to your reactions. Meanwhile, @Jeff_Emanuel’s intent has been clarified and an olive branch has been extended. I suggest we collectively move on.