The inaccessibility inside loops of variables defined in the global scope is driving me nuts. Do I really have to use the keyword global every time I refer to one in a “local” scope? I’d like to have a statement in global scope (or even better, a condition attached to the global variable) which says that it can be accessed everywhere, not just in the global scope. Is there a way to do this
Typically, you should avoid using global variables, but it should not require the global keyword in most cases. For example, the following runs in Julia 1.6.3:
x = 1
for i in 1:10
println("x = $x")
end
Is there a specific case where it is not working as expected?
If you’re not using functions - yes. This is by design, as anything can happen at any time in global scope, due to julia’s parallel dynamic nature and eval
. Passing arguments around explicitly makes it much easier for the compiler to optimize your code, as it doesn’t have to insert lookups to global variables at every access.
Some suggestions in this thread: Best solution to Julia's soft scope problem? - #5 by tim.holy
(probably there should be a warning at the very start of the Julia manual telling people to never, ever, use the global keyword, until you know the language enough to fully understand that it is unavoidably needed. The best advice is to never use it, there is almost always a better way to do things without it).
I understand completely. A few changes in your workflow will mean you never hit this problem again though.
Just remeber that:
- Softscope (i.e., what you find intuitive) applies to the REPL
- Softscope applies to Jupyter notebooks
- Softscope applies to VSCode when a
.jl
file is being executed inline (and I think debugged) - The behavior of code inside of functions is completely consisetnt with softscope
- If you run things as a
.jl
file with aninclude
etc. then you run into the thing you find confusing.
So note that this only happens in scripts that are called (and not executed in vscode inline). Everything else will be intuitive.
The solution to the problem at this point is:
- Feel free to have loops outside of functions in jupyter notebooks.
- Never write loops in
.jl
files that are not wrapped in a function. You would want to do this anyways for performance reasons. This will also ensure that things are consistent if you use the inline VS Code vs. theF5
to exdecute them. - If you ever use the
global
keyword and it wasn’t an intention design, then it probably means something is wrong. You probably should be wrapping something in a function There are almost no cases where that keyword is necessary for normal usage.
When I run this:
mutable struct Process
parent::Int64
generation::Int64
has_childen::Bool
start_time::Float64
end
function main()
process = Process(0,1,false,0)
println(fieldnames(Process))
process.has_children = true
end
main()
I get this:
%julia julia_bug.jl
Process(0, 1, false, 0.0)
(:parent, :generation, :has_childen, :start_time)
ERROR: LoadError: type Process has no field has_children
Stacktrace:
[1] setproperty!(x::Process, f::Symbol, v::Bool)
@ Base ./Base.jl:34
[2] main()
@ Main ~/code/hawkes/julia_bug.jl:12
[3] top-level scope
@ ~/code/hawkes/julia_bug.jl:14
in expression starting at /home/david/code/hawkes/julia_bug.jl:14
Looks like a bug. What am I missing?
You have a typo, in the definition of Process
, you write childen
instead of children
.
Aargh! Thanks for reading carefully. Why can’t I do that myself???
But that doesn’t seem to have nothing to do with the global scope, nor was it fixed by using the global
keyword. Did you post in a mistaken post?
It’s a double blunder. I first thought it was a scoping problem, and hurriedly posted that mistake (although I’ve run across the issue on a previous julia project – the “softscope” issue is one I haven’t encountered before because I’ve been a C++ programmer for years). Of course I could have saved everyone everyone a lot of time by just reading my code carefully. So mea culpa, and thanks so much for your quick responses!