
Scope revisited
A variable that is defined at the top level is said to have global scope.
The for, while, and try blocks (but not the if blocks) all introduce a new scope. Variables defined in these blocks are only known to that scope. This is called the local scope, and nested blocks can introduce several levels of local scope. However, global variables are not accessible in for and while loops.
Variables with the same name in different scopes can safely be used simultaneously. If a variable exists both in global and local scope, you can decide which one you want to use by prefixing them with the global or local keyword:
- global: This indicates that you want to use the variable from the outer, global scope. This applies to the whole of the current scope block.
- local: This means that you want to define a new variable in the current scope.
The following example will clarify this, as follows:
# code in Chapter 4\scope.jl x = 9 function funscope(n) x = 0 # x is in the local scope of the function for i = 1:n local x # x is local to the for loop x = i + 1 if (x == 7) println("This is the local x in for: $x") #=> 7 end end x println("This is the local x in funscope: $x") #=> 0 global x = 15 end funscope(10) println("This is the global x: $x") #=> 15
This prints out the following result:
This is the local x in for: 7 This is the local x in funscope: 0 This is the global x: 15
If the local keyword was omitted from the for loop, the second print statement would print out 11 instead of 7, as follows:
This is the local x in for: 7 This is the local x in funscope: 11 This is the global x: 15
What is the output when the global x = 15 statement is left out? In this situation, the program prints out this result:
This is the local x in for: 7 This is the local x in funscope: 11 This is the global x: 9
If you need to create a new local binding for a variable, use the let block. Execute the following code snippet:
anon = Array{Any}(undef, 2) for i = 1:2 anon[i] = ()-> println(i) i += 1 end
Here, both anon[1] and anon[2] are anonymous functions. When they are called with anon[1]() and anon[2](), they print 2 and 3 (the values of i when they were created plus one). What if you wanted them to stick with the value of i at the moment of their creation? Then, you have to use let and change the code to the following:
anon = Array{Any}(undef, 2) for i = 1:2 let i = i anon[i] = ()-> println(i) end i += 1 end
Now, anon[1]() and anon[2]() print 1 and 2, respectively. Because of let, they kept the value of i the same as when they were created.
The let statement also introduces a new scope. You can, for example, combine it with begin, like this:
begin local x = 1 let local x = 2 println(x) #> 2 end x println(x) #> 1 end
for loops and comprehensions differ in the way they scope an iteration variable. When i is initialized to 0 before a for loop, after executing for i = 1:10 end, the variable i is now 10:
i = 0 for i = 1:10 end println(i) #> 10
After executing a comprehension such as [i for i = 1:10], the variable i is still 0:
i = 0 [i for i = 1:10 ] println(i) #> 0