Hi,
New to Julia from MATLAB. I’ve been reading up on the local variable scope rules in Julia, but fail to understand the behaviour i see in the following example
Example code
u0 = 10 #The global scope variable
for k in 1:10
local local_u
#In the first iteration, local_u reads from the global variable
if k == 1
local_u = copy(u0)
end
#My main function call goes here - returns uk which i want to use in next iteration
uk = k*10*local_u
#Reassigning local_u to the result from the current iteration
local_u = copy(uk)
println("At end of iteration ", k, " local_u is ", local_u)
end
I can see that it goes through 1 iteration, but then throws the error when trying to execute.
I get the error message → UndefVarError: local_u not defined
So my Question is - Does the local variable (local_u) get destroyed after every iteration in the for loop ? Or am i misunderstanding something here.
You’re recreating local local_u in every iteration of the loop, thus overwriting its previous value. The behaviour you experience is therefore to be expected.
Why not just wrap it in a function?
u = 10 # global scope variable
function foo(u)
for k in 1:10
u = k*10*u # could also write u *= k*10
println("At the end of iteration $k local u is $u")
end
end
foo(u)
This is much simpler and you don’t have to deal with the local keyword, reassigning, copying or anything else.
Sorry, i do not fully understand. Then removing this line from my code should have solved th issue right? Even when i remove the line “Local local_u”, i get the same behaviour and error. It should be able to access the variable local_u from iteration k=1 during iteratio k=2 in this case, but doesn’t look like it.
My original code is trying to solve an Optimal Control Problem and simulate the plant, which are already in their own functions. I just put in k*10*local_u as a dummy line here instead of my function call. I am using the for loop to step through time in the main file, and hence did not want to wrap in a seperate function again.
julia> for i in 1:10
if i == 1
a = 2
end
@show a
end
This will throw the same error.
The way to think about this is that when you say a = 1, that assignment only exists for the first iteration of the loop. The other iterations of the loop don’t know that a variable a exists since it isn’t created in those other iterations.
If you want it to persist, you need to define it outside the loop. This is certainly a bit of a pain before 1.5 but now it works “as expected” when copied and pasted into the REPL.
Oh, that’s too bad. My mistake was that i misunderstood that the local variables were available until the “for loop” terminates. Thanks for the correction.
In this case, then I will use this approach then,
a = 1
for i in 1:10
global a1
a_temp = i*10*a #Get the next step of a. to be used in next iteration
@show a_temp
a = a_temp #assigning a_temp to be used in next iteration
end
If i may ask a followup question.
The line a1 = a_temp seems to be working instead of me having to use a = copy(a_temp).
Am i right in my understanding then that a = a_temp binds the variable names to the same underlying number, but when a_temp is destroyed at the end of iteration 1, the global variable a is able to retain the same value and does not end up cleared (even though the underlying local variable was cleared out)
Probably one thing more to note, is that arrays work differently than scalars, and the copy function plays an important role there:
julia> a = 1 ; b = [ 1, 1 ] ;
julia> for i in 1:2
a2 = a
b2 = b
a2 = 0
b2[1] = 0
end
julia> a
1
julia> b
2-element Array{Int64,1}:
0
1
Note that the value in the first position of the b vector changes, but the value of a does not, the variable a2 is local to the loop. Now using copy:
julia> a = 1 ; b = [ 1, 1 ] ;
julia> for i in 1:2
a2 = copy(a) # this is redudant for a scalar
b2 = copy(b)
a2 = 0
b2[1] = 0
end
julia> a
1
julia> b
2-element Array{Int64,1}:
1
1
julia> b2
ERROR: UndefVarError: b2 not defined
For the scalar, this is the same as before, but now b2 is a vector local to the loop, occupying a different space in memory, and altering its values do not alter the original b.
It isn’t required in Jupyter (and it never has been).
It (>= 1.5) isn’t required in the (normal) REPL or execute the code through any IDE that sends text to a normal REPL.
It is required if you use the REPL in vscode
It is required if you run it as a .jl file with include, etc.
My advice: stick to jupyter for this sort of thing where there are any top-level loops, and move to functions as soon as you no longer want to use jupyter
Yes, I fixed that already. In that context it was never required.
What changed is that if you need to assign a new value to the global variable, in 1.5 or greater you do not need to add the global anymore when using the REPL.
julia> a = 0
0
julia> for i in 1:2
global a # not required anymore in 1.5
a = a + 1
end
I would strongly advice to put your loop into a function, as @fbanning suggested, unless you are looping over very few elements.
The reason for this is that global variables are not type-stable and therefore you are getting bad performance - see the very first performance tip in Performance Tips · The Julia Language