Problem in variable definition in loop


#1

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

#2

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

#3

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.


#4

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.


#5

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.


#6

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

#7

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


#8

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?


#9

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.


#10

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.


#11

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.