### 5 Julia control

Julia control flow

Exception handling

Control flow provided in Julia

• Compound expression: begin and (;)
• Conditional evaluation: if-elseif-else and?: (ternary operator)
• Short-circuit evaluation: &&, || and chained comparisons
• Repeat evaluation: loop: while and for
• Exception handling: try-catch, error and throw
• Task (also called coroutine): yieldto

Compound expression

begin block

z = begin
x = 1
y = 2
x + y
end
>>3


(;)Chain

z = (x = 1; y = 2; x + y)


The value of these two expressions is the value of the last expression.

Conditional extremum

if x <y
println("x is less than y")
elseif x> y
println("x is greater than y")
else
println("x is equal to y")
end


The judgment condition must be trueorfalse of a

if 1
println("test...")
end
>>TypeError: non-boolean (Int64) used in boolean context


while loop

i = 5
while i <= 5
println(i)
i += 1
end


The above loop is written in a for loop as

for i = 1:5
println(i)
end


for can also traverse any container

for i in [1,2,3,4,5]
println(i)
end


other usage of for

for i in "abcd"
println(i)
end

for i in 1:2:10
println(i)
end

for i in 10:-2:1
println(i)
end

[x^2 for x in 1:4]
[x^2 for x ∈ 1:5]
[(x, x^2) for x ∈ 1:5]

for (i,x) in enumerate(1:4:20)
println(i, "", x)
end

collect(enumerate(1:4:20))


The usage of continue and break is basically the same as in other languages, so I won't talk about it here.

Variable scope

for i in 1:5
x = i
end


At this time, if you view the value of x outside the for loop, it will prompt error, because the variable x is only inside the for loop.

If you want to use x outside of for, you have to write

for i in 1:5
global x = i
end


If we define x externally in advance

x = 10
for i in 1:5
x = i
end


At this time, x is still 10, because x is local by default in for

Exception handling

sqrt(-1)
>>DomainError with -1.0:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).

Stacktrace:
[1] throw_complex_domainerror(::Symbol, ::Float64) at .\math.jl:31
[2] sqrt at .\math.jl:479 [inlined]
[3] sqrt(::Int64) at .\math.jl:505
[4] top-level scope at In[4]:1

try
sqrt(-1)
catch
println("pass")
end

sqrt_second(x) = try
sqrt(x[2])
catch y
if isa(y, DomainError)
sqrt(complex(x[2], 0))
elseif isa(y, BoundsError)
sqrt(x)
end
end


The finally statement usually causes the program to exit prematurely, making certain operations impossible to execute. The keyword finally can solve such problems. No matter how the program exits, the finally statement will always be executed.

f = open("file")
try
# operate on file f
finally
close(f)
end


It may be try, catchand finallyeven used together, finallyin catchexecution after handling exceptions.

Task (also called coroutine)

It is called symmetric coroutine, lightweight thread, cooperative multitasking, etc. (It is different from threads, which will be discussed in parallel computing later)

If a calculation is performed as a task, it is likely to be interrupted by other tasks. After the original task is resumed, it will continue to work from where it was interrupted. This process looks a lot like a function call, but there are two points. different:

1. Task switching does not require any space, so any number of tasks can be switched without considering stack issues.
2. Task switching can be done in any order.

Tasks are more suitable for the producer-consumer model, where one process is used to produce value and the other is used to consume value. The consumer cannot simply call the producer to get the value, because the execution time of the two is not necessarily coordinated. In the task, both can run normally.

Julia provides Channel to solve the problem of producer-consumer collaboration. In fact, Channel is a FIFO (first-in first-out) queue. Use the put!and take!function to achieve concretely.

function producer(c::Channel)
put!(c, "start")
for n=1:4
put!(c, 2n)
end
put!(c, "stop")
end


Then we create a Channel component to consume values.

chnl = Channel(producer)
take!(chnl)
>>"start"
take!(chnl)
>>2
take!(chnl)
>>4
take!(chnl)
>>6
take!(chnl)
>>8
take!(chnl)
>>"stop"


You can also use a forloop

for x in Channel(producer)
println(x)
end
>>start
2
4
6
8
sotp


Between the two calls put!(), the execution of the producer is suspended, and the consumer takes over control at this time.

A feature of the task is that as the task ends, the channel object will be automatically closed without human intervention.

Put the general function in the task:

function mytask(n)
for i=1:n
println(i)
end
end

>>false
1
2
3
4
5
6
7
8
9
10