Scope
Prerequisites: Functions
Scope decides where a variable is visible. Functions, loops,
let blocks, and comprehensions each create a new local scope;
the top level of a file is the global scope.
greeting = "hello" # global
function shout()
message = uppercase(greeting) # reads the global; message is local
return message
end
println(shout())
try
println(message)
catch err
println(typeof(err))
end
HELLO
UndefVarError
- A function can read global variables.
- Variables assigned inside a function are local to it and disappear when it returns.
Assigning inside a function creates a local
counter = 0
function bump()
counter = 10 # a new local, not the global
return counter
end
function bump_global()
global counter += 1
end
bump()
println(counter)
bump_global()
println(counter)
0
1
Use global when a function really must change a global — but it's
usually better to pass values in and return results out.
Loops at the top level of a script
In the REPL, a top-level loop can update a global variable. In a file, the same code is ambiguous, so Julia warns and treats the variable as a new local:
# illustrative — the error output is shortened below
total = 0
for i in 1:3
total += i
end
println(total)
┌ Warning: Assignment to `total` in soft scope is ambiguous because a
│ global variable by the same name exists: `total` will be treated as a
│ new local. Disambiguate by using `local total` to suppress this warning
│ or `global total` to assign to the existing global variable.
└ @ main.jl:3
ERROR: LoadError: UndefVarError: `total` not defined in local scope
Suggestion: check for an assignment to a local variable that shadows a global of the same name.
Stacktrace:
...
The fixes, from best to worst:
- Put the loop in a function (the normal Julia style — and much faster).
- Wrap it in a
letblock, or writeglobal total += iinside the loop.
function sum_to(n)
total = 0
for i in 1:n
total += i
end
return total
end
println(sum_to(3))
total = let t = 0
for i in 1:3
t += i
end
t
end
println(total)
6
6
let blocks
let creates a new local scope with its own variables, which is also a
handy way to keep temporary names out of the global scope.