Control flow
Contents
Control flow¶
Boolean types¶
Booleans are special data types that can have two values, true
or false
.
They are essential for conducting control flow.
Boolean operators (copied from here)
Expression |
Name |
---|---|
|
negation |
|
short-circuiting |
|
short-circuiting |
Numeric comparisons (copied partially from here)
Operator |
Name |
---|---|
|
equality |
|
inequality |
|
less than |
|
less than or equal to |
|
greater than |
|
greater than or equal to |
|
approximate equality with relative tolerance error |
|
programmatically identical equality comparison |
Most operators work exactly the same as in other languages.
2 == 2
true
4>5
false
When I was learning coding in Julia
, two operators were new to me: ≈
and ===
.
Operator ≈
compares two different objects given the tolerance error atol
:
≈(2000, 2000.1, atol=.5)
true
≈(2000, 2000.1; atol=.0001)
false
Operator ===
checks whether two objects are programmatically identical. In case of arrays or dictionaries, it means that we check whether two objects refer to the same memory slots. Illustrative example below:
x = [1,2]
y = x
z = deepcopy(x)
println("x==y: $(x==y)") #both objects have the same values
println("x==z: $(x==z)") #both objects have the same values
println("x===y: $(x===y)") #both objects refer to the same memory
println("x===z: $(x===z)") #both objects refer to different memory slots (even though they may have identical values)
x==y: true
x==z: true
x===y: true
x===z: false
The mentioned operators can be broadcasted. As a result we get arrays:
(1:1:3) .== (3:-1:1) #comparing [1 2 3] with [3 2 1]. It's true only for 2nd elements
3-element BitVector:
0
1
0
.![true, false] #notice the order of `.` and `!`
2-element BitVector:
0
1
Conditional evaluations¶
Implementation of if/elseif/else
is very standard and similar to other languages:
if expr1
sth1
elseif expr2
sth2
else
sth3
end
if
- dosth1
ifexpr1
is trueelseif
- dosth2
ifexpr2
is true andexpr1
is falseelse
- dosth3
if bothexpr1
andexpr2
are false
Example below:
if 2!=2
println("asd")
elseif 3>4
println("3>4")
elseif 5==10
println("5==10")
else
println("nothing")
end
nothing
?:
ternary operator¶
There is a ternary operator ?:
for short conditional evaluations.
Its syntax is cond ? sth1 : sth2
. The result of this operation conducted on scalar is: do sth1
if cond
is true and sth2
otherwise.
x = 4
even_x = x%2==0 ? "x is even" : "x is odd"
"x is even"
Suppose we want to create the CRRA utlity function in Julia
. It is defined as follows:
We can use ?
to define this function:
u(cₜ, η) = η==1 ? log(cₜ) : (cₜ^(1. -η)-1.)/(1. -η)
u (generic function with 1 method)
u(3,2)
0.6666666666666667
?:
can be nested, just like in an example below:
x = 4
x<5 ? (
x%2==0 ? println("x is smaller than 5 and is even") : #x<5 is true and x%2==0 is true
println("x is smaller than 5 and is odd") #x<5 is true and x%2==0 is false
) :
println("x is greater or equal to 5") #x<5 is false and x%2==0 is not evaluated
x is smaller than 5 and is even
We know that the CRRA function is well defined if \(\eta\geq 0.\) We can check this condition using nested ?
:
u(cₜ, η) = η≥0 ?
(η==1 ? log(cₜ) : (cₜ^(1. -η)-1. )/(1. -η)) :
@error "η=$η is not allowed!"
u (generic function with 1 method)
u(3, 2)
0.6666666666666667
u(3, -1)
┌ Error: η=-1 is not allowed!
└ @ Main In[13]:3
Elementwise ?:
¶
Note
Suppose that we want to perform a following mapping for \(x\in 1,2, \ldots, 10:\)
Such a task can be done relatively easily in other languages.
For instance in R
we get it by using ifelse
:
result <- ifelse(x%%2==0, -x^2, x^2 + 1) #this is `R` code. It will not work in `Julia`
We might be tempted to make elementwise comparisons using .?
.
x = collect( 1:10 );
result = ((x) .%2 .==0) .? -(x).^2 .: (x).^2.+1
syntax: space before "." not allowed in "((x .% 2) .== 0) ." at In[16]:2
Stacktrace:
[1] top-level scope
@ In[16]:2
[2] eval
@ ./boot.jl:360 [inlined]
[3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
@ Base ./loading.jl:1094
As we can see, it will not work the way we would like.
A solution to this problem is to use map
function with an anonymous function:
map(arg -> arg%2==0 ? -arg^2 : arg^2+1 , x)
10-element Vector{Int64}:
2
-4
10
-16
26
-36
50
-64
82
-100
This works as intended.
Short-circuit evaluations¶
Julia
exhibits lazy evaluation of formulas.
This means that operations are computed only if they are needed.
This property has some particular consequences for two operators, &&
and ||
.
Laziness of Julia
together with necessary condition for true
value in &&
and sufficient condition for false
in ||
can be used for conditional evaluations.
More precisely, the second (right-hand side) argument of &&
is evaluated if and only if the first (left-hand side) argument is true.
Similarly, the second (right-hand side) argument of ||
is not valuated if if the first (left-hand side) argument is false.
As the second argument we can put some evaluations that we would like to conduct subject to the left-hand side argument. Simple illustrations below:
(2+2==4) && println("(2+2==4) It's true");
(2+2==4) It's true
(2+2==5) && println("(2+2==5) It's true"); # the latter is not executed as (2+2==5) is false
(2+2==4) || println("(2+2==4) It's false"); # the latter is not executed as (2+2==4) is true
(2+2==5) || println("(2+2==5) It's false");
It's false