Global variables not visible within loops in scripts

All:

If I have a simple script that sets a variable at the top level, and then tries to modify the variable from within a loop, I get an error stating that the variable is not defined:

#!/usr/bin/env julia

i = 0
for j in 1:3
    i = i+1
    println(i, " ", j)
end

yields:

~$ ./test.jl
ERROR: LoadError: UndefVarError: i not defined
Stacktrace:
 [1] top-level scope at /home/dortley/test.jl:5 [inlined]
 [2] top-level scope at ./none:0
 [3] include at ./boot.jl:317 [inlined]
 [4] include_relative(::Module, ::String) at ./loading.jl:1041
 [5] include(::Module, ::String) at ./sysimg.jl:29
 [6] exec_options(::Base.JLOptions) at ./client.jl:229
 [7] _start() at ./client.jl:421
in expression starting at /home/dortley/test.jl:4

If I do the same code, but wrap it in a function, I get the behavior I expect. So the following works just fine:

#!/usr/bin/env julia

function go()
    i = 0
    for j in 1:3
        i = i+1
        println(i, " ", j)
    end
end

go()

Is this a bug, or are we not expected to declare globals at the top level of a script like that?

Thanks.
-David Ortley

3 Likes

In 1.0, you need to write global i = i + 1. Otherwise the for loop has a local called i which shadows the global variable i.

3 Likes

can we make this global here the default behavior? if not, is this due to performance concern or we think this is more useful/intuitive.

I think python/c++ in this case would imply i comes from outer scope.

4 Likes

This has been discussed here: https://github.com/JuliaLang/julia/issues/28789

2 Likes

Thanks for the replies.

So I read through the discussion on the issue posted by @RaulDurand and I think I follow. I’d like to summarize below to see if I understand the discussion correctly and also for the benefit of others:

  • For the REPL and scripts, global variables aren’t seen inside of top level loops because of the possible ambiguity between local variables.
  • Global variables ARE seen inside of if statements without the use of global (any others situations?)
  • The behavior is intended.
  • It is understood by the developers that there is some friction with that decision, no need for more pontification, even if well meaning. :slight_smile:
  • Currently, one can use [SoftGlobalScope.jl](https://github.com/stevengj/SoftGlobalScope.jl) or wrap stuff in a local scope such as a let block or function.
  • Something like SoftGlobalScope.jl will get implemented in Base for v1.1, though no change in language behavior is planned through all of v1.x

Did I get everything correct?

-David Ortley

1 Like

Well… There’s been some more discussion since a few hours ago :sweat_smile:

Fighting with my code by running individual blocks of code to manually debug the logic of the program, until I discover a new thing in Julia. :grin:
For loops have scopes too!

2 Likes