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.

And many more threads.

1 Like

I encountered same problem and because of my experience with other programming language which usually take more easy about scope specially in loop case, I was a little angry and also disappointed. Based on document, the reason is more clear for me and I think in some cases like software development, it’s not bad to restrict user, but still somehow it’s a hard decision.
One way to using function and avoiding issue with more localization of code. In original document use an example and use global variable to handle it, which is very dangerous and it’s better to not be used, because of general consequence of global parameter.
Anyway, thanks to discussing this issue, for many hours I was struggling with this issue and this discussion help me a lot :slight_smile:

3 Likes