Why do I get an error when I do 'run all', but not when running each line individually?

Viewed 68

I use Julia 1.6.2 & Juno, and I have this code:

println("0.5772156649015328606065120900824024310421")
jmax = 1000000
gamma = 0
j = 1

for j = jmax:-1:1
    gamma = gamma + 1.e0/j
end
gamma = gamma - log(jmax)
println("$gamma, reverse order sum $(jmax)")

There is no error when I run each line in order by using Ctrl+Enter. But I have an error and get the following message when I do 'run all' (Ctrl+Shift+Enter).

Warning: Assignment to 'gamma' in soft scope is ambiguous because a global variable by the same name exists: 'gamma' will be treated as a new local. Disambiguate by using 'local gamma' to suppress this warning or 'global gamma' to assign to the existing global variable.

ERROR: LoadError: UndefVarError: gamma not defined

I don't know why this difference happens. Can you explain about it?

2 Answers

The problem here is that Julia has two different ways to organise the "scope", the visibility of variables, according to the fact it is run interactively, like on the REPL or line-by-line in the editors, or not.

The full explanation is on the link you has been provided, but the question here is that you first define a global variable gamma and then you edit this variable inside a for loop, that introduces (like functions) their own scope.

In line-by-line mode the variable gamma you refer to within the for loop is considered the global variable you have already defined, and it is all fine.

In "whole script" execution mode however it is required that you explicitly indicate "I am referring to the global variable gamma", as this connection is not done automatically.

So, in your case, just change the line inside the for loop in:

global gamma = gamma + 1.e0/j

to explicitly indicate you want to work with the global gamma and not a possible (not-existing) local one. This will make it working in both the line-by-line and file-based run.

Extending the answer above:

You should wrap your code into a function.

Inside a function, gamma is a local variable, not a global, thus it is used in the for-loop (note that this is only true if a variable is defined in a function before the loop, variables only defined inside a loop are not visible outside).

Furthermore, in a function Julia is able to infer the types, thus calculation is much faster (can be a factor of 100).

fuction do_stuff()
    jmax = 1000000
    gamma = 0.0 # define it as a float for type stability!
    j = 1
    
    for j = jmax:-1:1
        gamma = gamma + 1.e0/j
    end
    gamma = gamma - log(jmax)
    println("$gamma, reverse order sum $(jmax)")
end
do_stuff()

The variable scoping rules seem unintuitive at first, but there are good reasons for them and they are in detail explained in the Julia manual.

Related