Why does the soft scope warning not appear in a nested loop?

Hello, I am confused because this basic loop yields a warning:

i = 5
for j in 1:5
    # ...
    i = "other_value"
    # ...
end
┌ 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.
└ @ main.jl:4

… which I understand. But the following yields no warning:

for i in 1:5
    # ...
    for j in 1:5
        # ...
        i = "other_value"
        # ...
    end
end

… and I’ve just struggle hard to find a bug because I inadvertently wrote something like this X) Is there a reason for the warning to exist in the former case, but not the latter?

In that case i belongs to the scope of the outer loop (thus a local scope).

The problem with the first one is that having a global i has a whole set of implications for type inference and performance (because i is global), and for that it has to be deal with differently.

2 Likes

Oh, okay, so there is something really special with the global scope, and this is what this warning is about. It is not just about “i belongs to the outer scope”. I understand now, thank you :slight_smile:

2 Likes

Yes, that is why it is highly recommended to avoid the use of global variables. If you wrap everything in a function, or a let block, for example, which define their own scope, you won’t get those warnings either.

2 Likes

Well, in this case I would rather have had the warning instead of my error silently passing X)

Uhm… not sure if I understand. In that case there would be no “error”, the variable would be modified as intended:

julia> function f()
           i = 1
           for j in 1:2
               i += 1
           end
           @show i
       end
f (generic function with 1 method)

julia> f()
i = 3
3

julia> let 
           i = 1
           for j in 1:2
               i += 1
           end
           @show i
       end
i = 3
3

Take a look at this: Scope of loops · JuliaNotes.jl

Haha yes exactly, but my intent was not to modify it :slight_smile: Picking i for the inner loop variable was an unfortunate name clash in my case. I’ll be more careful in the future ^ ^

1 Like

You can always declare a variable as local to avoid it picking up any previous definitions:

function f()
   i = 100
   for j in 1:2
       local i = 0
       i = i + j
   end
   println(i)
end

julia> f()
100
5 Likes