
Scope and constants
The region in the program where a variable is known is called the scope of that variable. Until now, we have only seen how to create top-level or global variables that are accessible from anywhere in the program. By contrast, variables defined in a local scope can only be used within that scope. A common example of a local scope is the code inside a function. Using global scope variables is not advisable for several reasons, notably the performance. If the value and type can change at any moment in the program, the compiler cannot optimize the code.
So, restricting the scope of a variable to local scope is better. This can be done by defining them within a function or a control construct, as we will see in the following chapters. This way, we can use the same variable name more than once without name conflicts.
Let's take a look at the following code fragment:
# code in chapter 2\scope.jl x = 1.0 # x is Float64 x = 1 # now x is Int y::Float64 = 1.0 # ERROR: syntax: type declarations on global variables are not yet supported function scopetest() println(x) # 1, x is known here, because it's in global scope y::Float64 = 1.0 # y must be Float64, this is not possible in global scope end scopetest() #> 1 #> 1.0 println(y) #> ERROR: UndefVarError: y not defined
Variable x changes its type, which is allowed, but because it makes the code type unstable, it could be the source of a performance hit. From the definition of y in the third line, we can see that type annotations can only be used in local scope (here, in the scopetest() function).
Some code constructs introduce scope blocks. They support local variables. We have already mentioned functions, but for, while, try, let, and type blocks can all support a local scope. Any variable defined in a for, while, try, or let block will be local unless it is used by an enclosing scope before the block.
The following structure, called a compound expression, does not introduce a new scope. Several (preferably short) sub-expressions can be combined in one compound expression if you start it with begin, as in this example:
x = begin a = 5 2 * a end # now x is 10 println(a) #> a is 5
After end, x has the value 10 and a is 5. This can also be written with ( ) as follows:
x = (a = 5; 2 * a) #> 10
The value of a compound expression is the value of the last sub-expression. Variables introduced in it are still known after the expression ends.
Values that don't change during program execution are constants, which are declared with const. In other words, they are immutable, and their type is inferred. It is a good practice to write their name in uppercase letters, like this:
const GC = 6.67e-11 # gravitational constant in m3/kg s2
Julia defines a number of constants, such as ARGS (an array that contains the command-line arguments), VERSION (the version of Julia that is running), and OS_NAME (the name of the operating system such as Linux, Windows, or Darwin), mathematical constants (such as pi and e), and Datetime constants (such as Friday, Fri, August, and Aug).
If you try to give a global constant a new value, you get a warning, but if you change its type, you get an error, as follows:
julia> GC = 3.14 Warning: redefining constant GC julia> GC = 10 ERROR: invalid redefinition of constant GC
So, global constants are more about type than value, which makes sense, because Julia gets its speed from knowing the correct types. If, however, the constant variable is of a mutable type (for example, Array, Dict (refer to Chapter 8, I/O, Networking, and Parallel Computing)), then you can't change it to a different array, but you can always change the contents of that variable:
julia> const ARR = [4,7,1] julia> ARR[1] = 9 julia> show(ARR) #> [9,7,1] julia> ARR = [1, 2, 3] Warning: redefining constant ARR
To review what we have learned in this chapter, we will play with characters, strings, and arrays in the following program (strings_arrays.jl):
using Statistics # a newspaper headline: str = "The Gold and Blue Loses a Bit of Its Luster" println(str) nchars = length(str) println("The headline counts $nchars characters") # 43 str2 = replace(str, "Blue" => "Red") # strings are immutable println(str) # The Gold and Blue Loses a Bit of Its Luster println(str2) println("Here are the characters at position 25 to 30:") subs = str[25:30] print("-$(lowercase(subs))-") # "-a bit -" println("Here are all the characters:") for c in str println(c) end arr = split(str,' ') show(arr)
#["The","Gold","and","Blue","Loses","a","Bit","of","Its","Luster"] nwords = length(arr) println("The headline counts $nwords words") # 10 println("Here are all the words:") for word in arr println(word) end arr[4] = "Red" show(arr) # arrays are mutable println("Convert back to a sentence:") nstr = join(arr, ' ') println(nstr) # The Gold and Red Loses a Bit of Its Luster # working with arrays: println("arrays: calculate sum, mean and standard deviation ") arr = collect(1:100) typeof(arr) #> Array{Int64,1} println(sum(arr)) #> 5050 println(mean(arr)) #> 50.5