# Problem in variable definition in loop

Dear all,

I don’t understand this behaviour. How come “j” is not defined in the second round
of the loop if it was defined on the first?

julia> for i in 1:2
if i == 1
j = 1
end
println("i = ", i)
println("j = ", j)
end
i = 1
j = 1
i = 2
ERROR: UndefVarError: j not defined

Because j never gets defined when i = 2 and it doesn’t exist outside of the loop either. The first time the loop runs j is created inside of the loop, but not in the global environment.

This works as expected

for i in 1:2
if i == 1
global j = 1
end
println("i = ", i)
println("j = ", j)
end
i = 1
j = 1
i = 2
j = 1
1 Like

Ok, lets be more specific, because this behaviour seems very strange to me. I want to define some vectors in the first iteration of my loop, because there is were I find out the size they must have. A minimal example would be:

for i in 1:2
if i == 1
n = 2 # Actually this is reading problem data.
x = zeros(n)
end
println("i = ", i)
println("x[1] = ", x[1])
end

declaring x as global does not seem reasonable to me, and this loop is thought to be inside a function, I do not want x to be a global variable at all.

In fortran this would be something like:

double precision, allocatable :: x(:)
do i = 1, 2
if i == 1 then
n = 2
allocate(x(2))
end if
write(*,*) i, x(1)
end do

That the definition does not work with a a scalar is disturbing to me, really:

do i = 1, 2
if i == 1 then
j = 2
end if
write(*,*) i, j
end do

That this code results in an error is very, very disturbing to me.

What happens if you actually wrap all of this in a function? You may also need to define x at the start of the function.

Exactly, I need to define x at the start of the function.

That makes things completely equivalent to Fortran, in which I need to declare the variables.

For a vector, I think I could use x = Vector{} instead of allocatable(x), but for a scalar it seems I have to define its value:

julia> function test()
j = 0
x = Vector{}
for i in 1:2
if i == 1
j = 1
x = zeros(3)
end
println("i = ", i)
println("j = ", j)
println("x = ", x)
end
end
end ; test()

This works as expected, although it seems to me that having to define an actual value for the scalar j is not ideal. Also, I am not sure if x = Vector{} is the best way to go there.

Thanks.

How about using local? For example…

function test()
local j, x
for i in 1:2
if i == 1
j = 1
x = zeros(3)
end
println("i = ", i)
println("j = ", j)
println("x = ", x)
end
end

Try it in a Jupyter notebook. Does the code behave then behave in the way you would expect?

Wrapping the code inside a function (which I always do because of the scoping rules of the repl), the two following solutions seem reasonable:

1. Assigning a value to the variable outside the loop
function test()
#x = Vector{} (commented to remove this error, pointed out by the next post)
x = 0.
j = 0
for i in 1:2
if i == 1
x = rand(3)
j = 1
end
println("i = ", i)
println("x = ", x, " j = ", j)
end
end
1. Or declaring a local:
function test()
local x
local j
for i in 1:2
if i == 1
x = rand(3)
j = 1
end
println("i = ", i)
println("x = ", x, " j = ", j)
end
end

Seems that the second option provides more information for the compiler, is that correct?

Just issuing

local j, x

works.

This, however, is wrong:

x = Vector{}

Here you are not declaring the type of the variable, instead you are assigning a type as the value of x:

julia> x = Vector{}
Array{T,1} where T

julia> typeof(x)
UnionAll

You could, if you like, add a type, like this:

local x::Vector{Float64}  # note ::, not =. Also Vector{} is the wrong type

but I don’t think the type annotation makes any difference.

4 Likes

Thank you, this is a very important corrrection indeed, and allows me to advance quite a bit on the understanding of the language. I am still getting used to the idea that variables can things of any kind.

The not-so-obvious scoping rules you see has been discussed quite a bit over the last year or so. It’s a contentious issue and as far as I am aware, no solution was agreed upon.