Best solution to Julia's soft scope problem?

For example, a loop like the below will consistently cause an error.

A = 5
for i in 1:10
    A = A+i;
end

Error message:

Assignment to `A` in soft scope is ambiguous because a global variable by the same name exists: `A` will be treated as a new local. Disambiguate by using `local A` to suppress this warning or `global A` to assign to the existing global variable.
**ERROR:** LoadError: UndefVarError: A not defined
Stacktrace:
[1] top-level scope

Other than wrapping everything up with a let and end, what is the best solution to this problem? It seems that they are not interested in fixing this in Julia 2.0?

Your post is a bit ambiguous about what you’re doing (it would help to be more specific), because if you just copy your code into a REPL it works fine on Julia 1.5 and higher AND it works inside a function. The only time you get that error is if you include it in a script (but I had to guess that’s what you were doing).

The thing to understand is that Julia is trying to coach you to better programming practice. Don’t work in global scope except when you’re playing around in the REPL. Many Matlabbers fall victim to this practice and it holds back their growth as good programmers. Get used to creating functions, think about design, testability, etc., and you’ll get better performance and cleaner code.

11 Likes

Thanks, Tim. Yes, the only time it gets me the error is when I include it in a script.

The problem of wrapping them into a function is that sometimes, I have dozens of input variables. The example is a much simplified one.

A solution is to create a struct that hold all of those variables, so that functions can have just one argument that makes all of the variables available.

4 Likes

All the more reason to use functions: loops at global scope have terrible performance, but loops in a function have amazing performance. The more data you’re working with, the more this will matter.

But it’s also worth asking if those dozen arguments might lead a more productive life with a certain amount of organization into structs, Dicts, etc.

This past Wednesday I taught a lecture that describes how thinking about testability can help clarify better ways of approaching code design: AdvancedScientificComputing/schedule_2021.md at main · timholy/AdvancedScientificComputing · GitHub (see the Oct. 20 session).

12 Likes

Even for smaller tasks, here is a tip: wrap everything in a function:

function job()

end

Use Revise and include the script with:

julia> using Revise

julia> includet("./job.jl") # note the t for track

julia> job() 

Now modify your script. You only need to run job() again to see the changes in action.

This is very practical even of you are only tuning the appearance of a plot, for example.

(Kudos to Tim)

6 Likes

This is a compromise between being technically correct and just doing it. This creates a local scope for you to work in.

let A = 5
    for i in 1:10
        A = A+i;
    end
    println(A)
    # Do other stuff that uses A
end

If you really want want the minimum fix, you can add a global declaration in the loop. I do not recommend it.

A = 5
for i in 1:10
    global A = A + 1
end
2 Likes

Tim, Many thanks for sharing the course material! :+1: I definitely want to take advantage of it.