Do I have to add a `global` before the counting variable in the `while` loop?

i = 0
while i <= 100
    println(i)
    i += 1
end

Write the above code in a julia script Test.jl and run it, in the REPL it reports the following error:

┌ Warning: Assignment to `i` in soft scope is ambiguous because a global variable by the same name exists: `i` will be treated as a new local. Disambiguate by using `local i` to suppress this warning or `global i` to assign to the existing global variable.        
└ @ d:\CodeTest\Test.jl:4
ERROR: UndefVarError: `i` not defined
Stacktrace:
 [1] top-level scope
   @ d:\CodeTest\Test.jl:3

I know adding a global before i += 1 can solve this problem, but I wonder if this is the typical solution to this kind of error in julia’s usage. In another word, I feel this feature of Julia language brings trouble when programming. Do I have to adapt to Julia, or there are some better ways in Julia to deal with this kind of use case?

Thanks!

This kind of use of globals

This is how scoping works, so using global is necessary if you don’t want to change the structure of your code. But the general recommendation is to wrap your code within a function.

There is actually a trick to run your code as is, but it’s using julia internals and is not officially supported. As you probably noted, you can run the initial code without a problem if it’s typed in the REPL. You can achieve the same effect when the code is in a file via:

import REPL
include(REPL.repl_ast_transforms[1], "your-script.jl")
1 Like

Try

let
  i = 0
  while i <= 100
      println(i)
      i += 1
  end
end

and the warning is gone.
If you need the value of i later on, use

i = let
  i = 0
  while i <= 100
      println(i)
      i += 1
  end
  i
end
3 Likes

Well, yes… :slight_smile: If you’re coming from another language, you’ll need to focus on the things which are different. - sometimes you have to unlearn things as well as learn things.

1 Like

Thanks for erveryone’s kind reply! They are all helpful to me.

Now I have another question. The error report says I have an undefined i in the 3rd line of my script, which corresponds to the command println(i). If I add a global i line above println(i), there will be no error or warning. This is understandable:

i = 0
while i <= 100
    global i
    println(i)
    i += 1
end

But if I only add the global in the 4th line before i += 1,

i = 0
while i <= 100
    println(i)
    global i += 1
end

I can’t understand why the UndefVarError: i not defined corresponding to the 3rd line println(i) also disappears. As we can see, I didn’t declare any global i before the 3rd line in the while loop, then how did println(i) recognize the i in this case?

I’m not sure if I expressed myself clearly…

You could write this, which probably is clearer:

i = 0
while i <= 100
    global i
    println(i)
    i += 1
end

thus, just specify that your reference to i is about the global variable just at the begining of the loop. (The while loop is parsed at all once, as I understand, that’s why you can use global at any point).

Yet, you should not do this, neither any other alternative that uses a global variable, most of the time. It is better if you write:

function myloop()
    i = 0
    while i <= 100
        i += 1
        # do your stuff here
    end
end
myloop() # call the function

This will allow Julia to compile your myloop() function entirely and the code will potentially be much faster. Additionally, if you use Revise, you can do

julia> using Revise

julia> includet("./myscript.jl") # note the t

julia> myloop()

and then any modification to the function will be tracked, and you just need to run myloop() again in the REPL to see the changes in action.

Concerning scopes, the manual section is this one: Scope of Variables · The Julia Language

I have some notes here with a simpler and personal account of that: Scope of loops · JuliaNotes.jl

3 Likes

Thank you very much for your professional answer! I will spend some time on digesting and absorbing. :handshake:

I can’t understand why the UndefVarError: i not defined corresponding to the 3rd line println(i) also disappears.

A type declaration within a scope block enforces an unchangeable type for the entire block. The declaration can occur anywhere within the block.

1 Like

I see. Thanks! :handshake: