 # 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 = ", x)
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.

And many more threads.

1 Like