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- dosth1ifexpr1is trueelseif- dosth2ifexpr2is true andexpr1is falseelse- dosth3if bothexpr1andexpr2are 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"
Example 6
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