I have an example that has me confused about scope. I define a variable current_header
which is inside a for loop
. My understanding is this variable should be in the scope of the for loop
. Furthermore this example works when running in the Debugger, but not in plain Julia. Here is the code:
scope_question.jl
using Debugger
struct FilePart
header::String
key::String
value::String
end
function processfile(lines::Vector{String})
file = FilePart[]
for line in lines
if startswith(line, "[") & endswith(line, "]")
current_header = line
println("Header: $current_header")
else
parts = split(line, "=")
key = strip(parts[1])
value = strip(parts[2])
println("key: $key | value: $value")
push!(file, FilePart(current_header, key, value))
end
end
print("finished with $(size(file,1)) values")
return file
end
lines = [
"[Test]"
"key1=value1"
]
println("Running in Debugger...")
@run processfile(lines)
println("*")
println()
println("Running Outside Debugger...")
processfile(lines)
println("*")
And the output I get is:
julia> include(“scope_question.jl”)
Running in Debugger…
Header: [Test]
key: key1 | value: value1
finished with 1 values*
Running Outside Debugger…
Header: [Test]
key: key1 | value: value1
ERROR: LoadError: UndefVarError: current_header not defined
As can be seen I get an UndefVarError for current_header
. What am I missing about scope here?
But why? As I understand a for loop
has a scope and current_header
is defined in that scope. So when I attempt to use it in the same for loop
shouldn’t it be defined?
It doesn’t have to be global (in fact, it shouldn’t be!), but it has to be defined outside the loop. The reason is that each iteration of a for loop is wrapped in a let
block. The variables defined inside it exist only until the end of the iteration.
4 Likes
From Scope of Variables · The Julia Language
In loops and comprehensions, new variables introduced in their body scopes are freshly allocated for each loop iteration, as if the loop body were surrounded by a let
block.
This will not work for instance
function foo()
for i in 1:5
if i == 1
x = 42
else
@show x
end
end
end
3 Likes
Ah, OK, thank you @tomerarnon!
Do you know why it works in Debugger.jl? Just curious.
Thanks @FedericoStra, I missed that part of the documentation.
No, I don’t honestly. Debugger works differently than normal execution (using an interpreter in many places) and maybe defines it’s own scope with its own variables. It’s worth checking if that behavior has been reported there already, and if not filing an issue.
The most obvious approach is to simply declare x
in the scope of the function:
function foo()
local x
for i in 1:5
if i == 1
x = 42
else
@show x
end
end
end
Edit: here is the previous version of my answer, which contains a wrong statement caused by some kind of hallucinations I must have had while staring at the REPL for too long.
What I find less than desirable is that to make my example work one needs to write something like
function foo()
x = 0
for i in 1:5
if i == 1
x = 42
else
@show x
end
end
end
The most obvious approach of simply declaring x
in the scope of the function
function foo()
local x
for i in 1:5
if i == 1
x = 42
else
@show x
end
end
end
is not sufficient and doesn’t work unfortunately.
2 Likes
Your second foo
works fine.
1 Like
Uhm… I don’t know what kind of hallucinations I must have had… I was probably working in a dirty workspace and used the wrong definition. You are perfectly right of course.
2 Likes