Search code examples
scopejulia

Unexpected behaviour in Julia's soft scope


I read the Julia documentation about scope, but I'm getting unexpected behaviour for the non-interactive case (i.e. running a script from the command line, not the REPL). The documentation says:

Soft scope: If x is not already a local variable and all of the scope constructs containing the assignment are soft scopes (loops, try/catch blocks, or struct blocks), the behavior depends on whether the global variable x is defined:

  • if global x is defined, the assignment is considered ambiguous:
    • in non-interactive contexts (files, eval), an ambiguity warning is printed and a new local is created;

But here's a MWE of code I ran from a file:

x_int = 0
x_arr = [0]

for i in 1:1
    x_int = 1
    x_arr[1] = 1
end

println(x_int)
println(x_arr)

Output:

0
[1]

To me, this is unexpected for two reasons:

  1. For x_int, a local variable was created, but no ambiguity warning was printed.
  2. For x_arr[1], instead of creating a new local variable, the global variable was modified.

This doesn't make sense to me :(


Solution

  • Set Up

    For your example, you set up:

    x_int = 0
    x_arr = [0]
    
    for i in 1:1
        x_int = 1
        x_arr[1] = 1
    end
    
    println(x_int)
    println(x_arr)
    

    Running Non-Interactively

    To run this non-interactively, lets save this and run the file with include() in the REPL.

    julia> include("Drive:/Path/To/Code/FileNameHere.jl")
    ┌ Warning: Assignment to `x_int` in soft scope is ambiguous because a global variable by the same name exists: `x_int` will be treated as a new local. Disambiguate by using `local x_int` to suppress this warning or `global x_int` to assign to the existing global variable.
    └ @ Drive:/Path/To/Code/FileNameHere.jl:5
    0
    [1]
    

    We can also run the file directly (outside of the REPL), if needed. In Command Prompt (or whatever console your system is using), we can simply type the name of the file with julia NameOfFile

    Drive:/Path/To/Your/PWD>julia Drive:/Path/To/Code/FileNameHere.jl
    
    ┌ Warning: Assignment to `x_int` in soft scope is ambiguous because a global variable by the same name exists: `x_int` will be treated as a new local. Disambiguate by using `local x_int` to suppress this warning or `global x_int` to assign to the existing global variable.
    └ @ Drive:/Path/To/Code/FileNameHere.jl:5
    0
    [1]
    

    Explanation of Behavior

    These are equivalent, and both give a warning for ambiguous scoping. We are expecting the global "version" of x_int, because the assignment on line 5 created a new local variable contained to that scope... and that is what we receive. You mentioned that a warning was not created on your device. If that is so, then your minimal example is not representative, and likely means that you did not have any scoped variable ambiguity in your original project.

    To understand why the x_arr[1] is returning the value you assigned in your soft scope, and why that is expected, we have to realize that you aren't actually creating a variable on line 6. In Julia, x_arr[index] = val is shorthand for setindex!(x_arr,val,index). This operation is directly changing the variable x_arr, not creating a new variable of any kind, and so scope is not relevant in this case. So we expect our println on line 10 to print the value that we most recently set it to, which it does.