Dear all:
I wonder why is the UndefVarError, and, is the Suggestion accurate?
julia> function test(C)
count = 1
v = Function[]
while count < C
local item
f = function()
println("I'm ", item[])
end
push!(v, f)
if count == 1
item = [count]
else
item[] += 1
end
map(x -> x(), v)
count += 1
end
end
julia> test(2)
I'm 1
julia> test(3)
I'm 1
ERROR: UndefVarError: `item` not defined in local scope
Suggestion: check for an assignment to a local variable that shadows a global of the same name.
Stacktrace:
[1] test(C::Int64)
@ Main .\REPL[1]:13
[2] top-level scope
@ REPL[3]:1
How to analyze the item, is it a local variable in one pass, or is it a local variable in all C-1 passes.
(by āpassā I mean one go from top to bottom within the while).
It always helps to form a minimal reproducible example. Get rid of all unnecessary lines so you can focus on the underlying issue.
Hereās one example:
julia> function test()
for i in 1:2
local item
if i == 1
item = [i]
else
item[] += 1
end
end
end
test (generic function with 2 methods)
julia> test()
ERROR: UndefVarError: `item` not defined in local scope
Suggestion: check for an assignment to a local variable that shadows a global of the same name.
Stacktrace:
One the first iteration, you declare local item and initialise it.
On the second iteration, you declare a new local item, and then attempt item[] += 1, which tries to read item[]. But because of local item, the variable does not persist between iterations and so it doesnāt exist in iteration 2.
Change where you put the local:
julia> function test()
local item
for i in 1:2
if i == 1
item = [i]
else
item[] += 1
end
end
return item
end
test (generic function with 2 methods)
julia> test()
1-element Vector{Int64}:
2
There is no ambiguity in this caseāthe three aās are the same name. This case is not confusing to users.
This is not the case for while/for, people needs to understand that if you have 10 iterations, then the local (user-specified) names in the loop body are not identical.
(My thoughts are also updated in the Github link above)
Note that the local scope of a for loop body is no different from the local scope of an inner function. This means that we could rewrite this example so that the loop body is implemented as a call to an inner helper function and it behaves the same way:
This may be theoretically equivalent. But would anyone write this conversion in practice? e.g. due to performance issues? Is the plain loop faster? Iām not very clear about this.
Anyway, I think the stress is on learning a skill to producing the predictable final result.
To be honest Iām having difficulty understanding some parts of that manual, e.g.
begin
local c
c += 1
end
It says begin block will not introduce a scope. But why is here a local?
Anyway, I have no chance using begin, so I would skip it.
how many different entities nameditem exist in the following code
function test()
item = 0
for i in 1:2
local item
if i == 1
item = [i]
else
item[] += 1
end
end
end
test()
It is possible for him to answer: Oh, the function test introduce a local scope, there is one outer item being associated to 0. Oh, I also see the for loop introduce an inner local scope and there is also an local item inside. So if there are no global name item elsewhere, the conclusion is:
there are 2 different entities named item here, both are non-global.
(Yes, surelyāI asked ChatGPT, who answered 2.)
But in reality, the proper answer is 3, given Oscarās answer in #2 post.
Anyway, I think my comprehension still needs to be advancedātherefore I give up the Github actions, giving way to people who are more experienced.
Edit: I took a closer look at ChatGPTās answer, and find itās even worse
An if you call the function twice, itās ⦠6? Or do you want repeated executions of the scope in the loop body to count multiple times, but not repeated execution of the scope in the function? What about repeated execution of let? Are there 10 scopes with b in this function?
function f()
i = 1
a = 0
@label L
let b = i^2
a += b
end
i += 1
if i < 10
@goto L
end
return a
end
Perhaps in the sense of dynamic scopes, but not the lexical scopes which are used in julia.
The preceding description is pretty much all there is to it:
If a top-level expression contains a variable declaration with keyword local , then that variable is not accessible outside that expression.
So while a begin block doesnāt make a local scope, a local declaration makes a variable only last in that scope, similar to how uncaptured local variables only last in their home local scope. The Manual currently does not describe this as a local variable, whether directly or indirectly. However, it does currently behave similarly to a local variable, even if the capture and boxing are implemented differently for global functions.
julia> begin
x = 1 # normal global
f() = x
print(f(), ", ")
let # rules say this would reassign outer locals
x = 10
end
local y = 2
g() = y
println(g())
let
y = 20
end
nothing
end
1, 2
julia> f(), g() # local y got reassigned
(1, 20)