Skip to content
AgileLogics
5 min read

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:

  1. Put the loop in a function (the normal Julia style — and much faster).
  2. Wrap it in a let block, or write global total += i inside 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.