Julia: Tutorial & Code-Collection¶
Source: https://github.com/markomlikota/CodingSoftware
MIT License, © Marko Mlikota, https://markomlikota.github.io
Object-Scopes¶
To make sure the following section fulfils its purpose, exit and re-start Julia before going over this section (in order to delete all objects created so far).
In [1]:
# A for-loop introduces a local scope.
# This means that object definitions that occur inside the for-loop
# are visible only inside the for-loop, not in the global scope.
# Consider the following example:
for ii = 1:2
q1a = ii
println("q1a = ", q1a)
end
println("q1a = ", q1a)
q1a = 1 q1a = 2
UndefVarError: `q1a` not defined Stacktrace: [1] top-level scope @ In[1]:10
In [2]:
# To create an object in the for-loop and save it for the global scope, declare it as global:
for ii = 1:2
global q1b = ii
println("q1b = ", q1b)
end
println("q1b = ", q1b)
q1b = 1 q1b = 2 q1b = 2
In [3]:
# In contrast,
# when the object that is changed inside the for-loop
# is already defined before the for-loop,
# the changes are visible in the global scope:
q1c = 5
for ii = 1:2
q1c = ii
println("q1c = ", q1c)
end
println("q1c = ", q1c)
q1c = 1 q1c = 2 q1c = 2
In [4]:
# The same holds true for while-loops:
ii = 1
while ii < 3
q2a = ii
println("q2a = ", q2a)
ii += 1
end
println("q2a = ", q2a)
ii = 1
while ii < 3
global q2b = ii
println("q2b = ", q2b)
ii += 1
end
println("q2b = ", q2b)
ii = 1
q2c = 5
while ii < 3
q2c = ii
println("q2c = ", q2c)
ii += 1
end
println("q2c = ", q2c)
q2a = 1 q2a = 2
UndefVarError: `q2a` not defined Stacktrace: [1] top-level scope @ In[4]:9
In [5]:
# The same holds true for evaluated functions ...:
function fMyFun(x)
q3a = 2 * x
return x^2
end
fMyFun(4)
println("q3a = ", q3a)
function fMyFun(x)
global q3b = 2 * x
return x^2
end
fMyFun(4)
println("q3b = ", q3b)
UndefVarError: `q3a` not defined Stacktrace: [1] top-level scope @ In[5]:8
In [6]:
# ... though, in contrast to for- and while-loops,
# non-global (re-)definitions inside the function are never visible in the outer scope,
# not even if the object was defined beforehand:
q3c = 5
function fMyFun(x)
q3c = 2 * x
return x^2
end
fMyFun(4)
println("q3c = ", q3c)
q3c = 5
In [7]:
# Conditionals do not introduce a local scope.
In [8]:
# Local scopes imply that objects created only in specific iterations
# are not visible to other iterations: e.g.
for ii = 1:3
ii == 1 ? q1d = 5 : nothing
println("Iteration ", ii, ": q1d = ",q1d)
end
# To make them visible, declare object as global.
Iteration 1: q1d = 5
UndefVarError: `q1d` not defined Stacktrace: [1] top-level scope @ ./In[8]:6
In [9]:
# Local scopes also imply that objects created in an "inner local scope"
# are not visible to the "outer local scope":
for ii = 1:2
for jj = 1:2
q1e = jj
end
println("q1e = ",q1e)
end
# In contrast, objects created in the "outer local scope"
# are visible to the "inner local scope":
for ii = 1:2
q1g = ii
for jj = 1:2
println("q1g = ",q1g)
end
end
# Due to local scopes,
# nested for-loops do not always give the same as "compact" for-loops:
# e.g.
for ii = 1:2
for jj = 3:4
println((ii,jj))
ii = 0
end
end
for ii = 1:2, jj = 3:4
println((ii,jj))
ii = 0
end
UndefVarError: `q1e` not defined Stacktrace: [1] top-level scope @ ./In[9]:8
In [10]:
# For functions, it's slightly different;
# like for for- and while-loops,
# objects created in an "inner local scope" are not visible to the "outer local scope" ...:
function fMyInnerFun1(x)
z = 5
return x^2
end
function fMyOuterFun1(w)
result = fMyInnerFun1(w/3)
return z * result
end
fMyOuterFun1(6)
UndefVarError: `z` not defined Stacktrace: [1] fMyOuterFun1(w::Int64) @ Main ./In[10]:14 [2] top-level scope @ In[10]:18
In [11]:
# ... but, in contrast to for- and while-loops,
# objects created in an "outer local scope" are not visible to the "inner local scope":
function fMyInnerFun2(x)
return y * x^2
end
function fMyOuterFun2(w)
y = 5
result = fMyInnerFun2(w/3)
return result
end
fMyOuterFun2(6)
y = 10
fMyOuterFun2(6)
# will always use the globally assigned value to y;
# the definition of y inside fMyOuterFun2 doesn't do anything!
UndefVarError: `y` not defined Stacktrace: [1] fMyInnerFun2(x::Float64) @ Main ./In[11]:5 [2] fMyOuterFun2(w::Int64) @ Main ./In[11]:12 [3] top-level scope @ In[11]:18
In [12]:
# This has important implications for "parameters" that appear in functions.
# When defining functions, one has to take a stand whether to include such parameters
# explicitly as arguments of the function or let the function use them implicitly.
# If the parameters are used explicitly, every time such functions are evaluated,
# they will use the supplied values for these parameters.
# If the parameters are used implicitly, every time such functions are evaluated,
# they will use the globally assigned values for these parameters.
# Therefore, implicitly used objects are o.k. as long as they are only changed in the global scope.
# If in doubt, specify parameters as explicit arguments.
Try Exercises 7.a.i - 7.a.ii