### 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 `true`or`false` 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:
 throw_complex_domainerror(::Symbol, ::Float64) at .\math.jl:31
 sqrt at .\math.jl:479 [inlined]
 sqrt(::Int64) at .\math.jl:505
 top-level scope at In:1

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

sqrt_second(x) = try
sqrt(x)
catch y
if isa(y, DomainError)
sqrt(complex(x, 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`, `catch`and `finally`even used together, `finally`in `catch`execution 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 `for`loop

```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