# Introducing Julia/Controlling the flow

## Contents

- 1 Different ways to control the flow
- 2 Ternary expressions
- 3 Boolean switching expressions
- 4 If and Else
- 5 For loops and iteration
- 6 While loops
- 7 Exceptions
- 8 Do block

### Different ways to control the flow[edit]

Typically each line of a Julia program is evaluated in turn. There are various ways to control and modify the flow of evaluation. These correspond with the constructs used in other languages:

**ternary**and**compound**expressions**Boolean**switching expressions**if elseif else end**- conditional evaluation**for end**- iterative evaluation**while end**- iterative conditional evaluation**try catch error throw**exception handling**do**blocks

### Ternary expressions[edit]

Often you'll want to do job A (or call function A) if some condition is true, or job B (function B) if it isn't. The quickest way to write this is using the ternary operator ("?" and ":"):

```
julia> x = 1
1
julia> x > 3 ? "yes" : "no"
"no"
julia> x = 5
5
julia> x > 3 ? "yes" : "no"
"yes"
```

Here's another example:

```
julia> x = 0.3
0.3
julia> x < 0.5 ? sin(x) : cos(x)
0.29552020666133955
```

and Julia returned the value of `sin(x)`

, because x was less than 0.5. `cos(x)`

wasn't evaluated at all.

### Boolean switching expressions[edit]

Boolean operators let you evaluate an expression if a condition is true. You can combine the condition and expression using `&&`

or `||`

. `&&`

means "and", and `||`

means "or". Since Julia evaluates expressions one by one, you can easily arrange for an expression to be evaluated only if a previous condition is true or false.

The following example uses a Julia function that returns true or false depending on whether the number is odd: `isodd(n)`

.

With `&&`

, both parts have to be true, so we can write this:

```
julia> isodd(1000003) && warn("That's odd!")
WARNING: That's odd!
julia> isodd(1000004) && warn("That's odd!")
false
```

If the first condition (number is odd) is true, the second expression is evaluated. If the first isn't true, the expression isn't evaluated, and just the condition is returned.

With the `||`

operator, on the other hand:

```
julia> isodd(1000003) || warn("That's odd!")
true
julia> isodd(1000004) || warn("That's odd!")
WARNING: That's odd!
```

If the first condition is true, there's no need to evaluate the second expression, since we already have the one truth value we need for "or", and it returns the value true. If the first condition is false, the second expression is evaluated, because that one might turn out to be true.

This type of evaluation is also called "short-circuit evaluation".

### If and Else[edit]

For a more general — and traditional — approach to conditional execution, you can use `if`

, `elseif`

, and `else`

. If you're used to other languages, don't worry about white space, braces, indentation, brackets, semicolons, or anything like that, but remember to finish the conditional construction with `end`

.

```
julia> name = "Brinkley"
"Brinkley"
julia> if name == "Jeeves"
println("Very Good Jeeves")
elseif name == "Brinkley"
println("Thank you, Brinkley")
println("and shut the door behind you")
else
println("Fine, just ignore me")
end
Thank you, Brinkley
and shut the door behind you
```

The `elseif`

and `else`

parts are optional too:

```
julia> name = "Jeeves"
julia> if name == "Jeeves"
println("Very Good Jeeves")
end
Very Good Jeeves
```

Just don't forget the `end`

!

How about 'switch' and 'case' statements? Well, you don't have to learn the syntax for those, because they don't exist!

#### ifelse[edit]

There's an `ifelse`

function, too. It looks like this in action:

```
julia> s = ifelse(false, "hello", "goodbye") * " world"
```

`ifelse`

is an ordinary function, which evaluates all the arguments, and returns the second or third, depending on the value of the first. With the conditional `if`

or `? ... :`

, only the expressions in the chosen route are evaluated.

### For loops and iteration[edit]

Working through a list or a set of values or from a start value to a finish value are all examples of iteration, and the `for`

... `end`

construction can let you iterate through a number of different types of object, including ranges, arrays, sets, dictionaries, and strings.

Here's the standard syntax for a simple iteration through a range of values:

```
julia> for i in 0:10:100
println(i)
end
0
10
20
30
40
50
60
70
80
90
100
```

The variable `i`

takes the value of each element in the array (which is built from a range object) in turn — here stepping from 0 to 100 in steps of 10.

```
julia> for color in ["red", "green", "blue"] # an array
print(color, " ")
end
red green blue
```

```
julia> for letter in "julia" # a string
print(letter, " ")
end
j u l i a
```

```
julia> for element in (1, 2, 4, 8, 16, 32) # a tuple
print(element, " ")
end
1 2 4 8 16 32
```

```
julia> for i in Dict("A"=>1, "B"=>2) # a dictionary
println(i)
end
"B"=>2
"A"=>1
```

```
julia> for i in Set(["a", "e", "a", "e", "i", "o", "i", "o", "u"])
println(i)
end
e
o
u
a
i
```

We haven't yet met sets and dictionaries, but iterating through them is exactly the same.

You can iterate through a 2D array, stepping "down" through column 1 from top to bottom, then through column 2, and so on:

```
julia> a = reshape(1:100, (10, 10))
10x10 Array{Int64,2}:
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99
10 20 30 40 50 60 70 80 90 100
julia> for n in a
print(n, " ")
end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
```

You can use `=`

instead of `in`

.

##### Iterating over an array and updating it[edit]

When you're iterating over an array, the array is checked each time through the loop, in case it's changed. A mistake you should avoid making is to use `push!`

to make an array grow in the middle of a loop. Run the following text carefully, and be ready to `Ctrl-C`

when you've seen enough (otherwise your computer will eventually crash):

```
julia> c = [1]
1-element Array{Int64,1}:
1
julia> for i in c
push!(c, i)
@show c
sleep(1)
end
c = [1,1]
c = [1,1,1]
c = [1,1,1,1]
...
```

#### Loop variables and scope[edit]

The variable that steps through each item — the 'loop variable' — can be either a variable that already exists, in which case it stays around after the loop finishes, or a variable that doesn't currently exist (in the current scope), in which case it disappears as soon as the loop finishes.

Here's a comparison:

```
julia> v = 42
42
julia> for v in 1:5 # v is already defined, so it's just re-used for looping
println(v)
end
1
2
3
4
5
julia> v
5
```

`v`

existed before the loop, and exists after the loop — its value was changed by the iteration process. However:

```
julia> w
ERROR: w not defined
julia> for w in 1:5 # w is now defined
println(w)
end
1
2
3
4
5
julia> w
ERROR: w not defined
```

Here, `w`

didn't exist before the loop, and doesn't exist after the loop.

The difference between the two is worth noting. The advantage of the first approach is that you can find out the final value of the loop variable after the loop's finished.

#### Fine tuning the loop: Continue[edit]

Sometimes on a particular iteration you might want to skip to the next value. You can use `continue`

to skip the rest of the code inside the loop and start the loop again with the next value.

```
julia>for i in 1:10
if i % 3 == 0
continue
end
println(i) # this and subsequent lines are
# skipped if i is a multiple of 3
end
1
2
4
5
7
8
10
```

#### Comprehensions[edit]

This oddly-named concept is simply a way of generating and collecting items. In mathematical circles you say something like:

"Let S be the set of all elements n where n is greater than or equal to 1 and less than or equal to 10".

In Julia, you can write this as:

```
julia> S = Set([n for n in 1:10])
Set([7,4,9,10,2,3,5,8,6,1])
```

and the `[n for n in 1:10]`

construction is called **array comprehension** or **list comprehension** ('comprehension' in the sense of 'getting everything' rather than 'understanding'). The outer brackets collect together the elements generated by evaluating the expression placed before the `for`

iteration. Instead of `end`

, use a square bracket to finish.

```
julia> [i^2 for i in 1:10]
10-element Array{Int64,1}:
1
4
9
16
25
36
49
64
81
100
```

The type of elements can be specified:

```
julia> Complex128[i^2 for i in 1:10]
10-element Array{Complex{Float64},1}:
1.0+0.0im
4.0+0.0im
9.0+0.0im
16.0+0.0im
25.0+0.0im
36.0+0.0im
49.0+0.0im
64.0+0.0im
81.0+0.0im
100.0+0.0im
```

But Julia can work out the types of the results you're producing:

```
julia> [(i, sqrt(i)) for i in 1:10]
10-element Array{Tuple{Int64,Float64},1}:
(1,1.0)
(2,1.41421)
(3,1.73205)
(4,2.0)
(5,2.23607)
(6,2.44949)
(7,2.64575)
(8,2.82843)
(9,3.0)
(10,3.16228)
```

Here's how to make a dictionary via comprehension:

```
julia> Dict(string(Char(i + 64)) => i for i in 1:26)
Dict{String,Int64} with 26 entries:
"Z" => 26
"Q" => 17
"W" => 23
"T" => 20
"C" => 3
"P" => 16
"V" => 22
"L" => 12
"O" => 15
"B" => 2
"M" => 13
"N" => 14
"H" => 8
"A" => 1
"X" => 24
"D" => 4
"G" => 7
"E" => 5
"Y" => 25
"I" => 9
"J" => 10
"S" => 19
"U" => 21
"K" => 11
"R" => 18
"F" => 6
```

Next, here are two iterators in a comprehension, separated with a comma, which makes generating tables very easy. Here we're making a tuple-table:

```
julia> [(r,c) for r in 1:5, c in 1:2]
5×2 Array{Tuple{Int64,Int64},2}:
(1,1) (1,2)
(2,1) (2,2)
(3,1) (3,2)
(4,1) (4,2)
(5,1) (5,2)
```

`r`

goes through five cycles, once for every value of `c`

. Nested loops work in the opposite manner. Here the column-major order is respected, as shown when the array is filled with nanosecond time values:

```
julia> [Int(time_ns()) for r in 1:5, c in 1:2]
5×2 Array{Int64,2}:
1223184391741562 1223184391742642
1223184391741885 1223184391742817
1223184391742067 1223184391743009
1223184391742256 1223184391743184
1223184391742443 1223184391743372
```

You can supply a test expression as well to filter the production. For example, produce all the integers between 1 and 100 that are exactly divisible by 7:

julia> [x for x in 1:100 if x % 7 == 0] 14-element Array{Int64,1}: 7 14 21 28 35 42 49 56 63 70 77 84 91 98

##### Generator expressions[edit]

Like comprehensions, generator expressions can be used to produce values from iterating a variable, but, unlike comprehensions, the values are produced on demand.

julia> sum(x^2 for x in 1:10) 385

julia> collect(x for x in 1:100 if x % 7 == 0) 14-element Array{Int64,1}: 7 14 21 28 35 42 49 56 63 70 77 84 91 98

#### Enumerating arrays[edit]

Often you want to go through an array element by element while also keeping track of the index number of each element. The `enumerate()`

function gives you an **iterable** version of something, producing both an index number and the value at each index number:

```
julia> m = rand(0:9, 3, 3)
3x3 Array{Int64,2}:
9 2 9
3 4 3
6 1 1
julia> [i for i in enumerate(m)]
9-element Array{(Int64,Any),1}:
(1,9)
(2,3)
(3,6)
(4,2)
(5,4)
(6,1)
(7,9)
(8,3)
(9,1)
```

The array is checked for possible changes at each iteration of the loop.

#### Zipping arrays[edit]

Sometimes you want to work through two or more arrays at the same time, taking the first element of each array first, then the second, and so on. This is possible using the well-named `zip()`

function:

```
julia>for i in zip(0:10, 100:110, 200:210)
println(i)
end
(0,100,200)
(1,101,201)
(2,102,202)
(3,103,203)
(4,104,204)
(5,105,205)
(6,106,206)
(7,107,207)
(8,108,208)
(9,109,209)
(10,110,210)
```

You'd think it would all go wrong if the arrays were different sizes. What if the third array is too big?

```
julia> for i in zip(0:10, 100:110, 200:215)
println(i)
end
(0,100,200)
(1,101,201)
(2,102,202)
(3,103,203)
(4,104,204)
(5,105,205)
(6,106,206)
(7,107,207)
(8,108,208)
(9,109,209)
(10,110,210)
```

but Julia isn't fooled — any oversupply in any one of the arrays is handled gracefully.

```
julia> for i in zip(0:15, 100:110, 200:210)
println(i)
end
(0,100,200)
(1,101,201)
(2,102,202)
(3,103,203)
(4,104,204)
(5,105,205)
(6,106,206)
(7,107,207)
(8,108,208)
(9,109,209)
(10,110,210)
```

#### Iterable objects[edit]

The "for something in something" construction is the same for everything that you can iterate through: arrays, dictionaries, strings, sets, ranges, and so on. In Julia this is a general principle: there are a number of ways in which you can create an "iterable object", an object that is designed to be used as part of the iteration process that provides the elements one at a time.

The most obvious example we've already met is the range object. It doesn't look much when you type it into the REPL:

```
julia> 0:2:100
0:2:100
```

But it yields the numbers on demand, when you start iterating:

```
julia> [i for i in 0:2:100]
51-element Array{Int64,1}:
0
2
4
6
8
10
12
14
16
18
20
22
24
26
28
⋮
74
76
78
80
82
84
86
88
90
92
94
96
98
100
```

Should you want the actual numbers from a range (or other iterable object), you can use `collect()`

:

```
julia> collect(0:25:100)
5-element Array{Int64,1}:
0
25
50
75
100
```

This might be helpful when you have iterable objects created by other Julia functions. For example, `permutations()`

creates an iterable object containing all the permutations of an array. You could use `collect()`

to grab them and make a new array.

```
julia> collect(permutations(1:4))
24-element Array{Array{Int64,1},1}:
[1,2,3,4]
[1,2,4,3]
…
[4,3,2,1]
```

Of course, there's a good reason why iterator objects don't produce all the values from the iteration at the same time: memory and performance. A range object doesn't take up much room, even if iterating over it might take ages (depending on how big the range is). If you generate all the numbers at once, rather than only producing them when they're needed, they all have to be stored somewhere…

Julia provides iterable objects for working with other types of data. For example, when you're working with files, you can treat an open file as an iterable object:

```
for line in eachline(filehandle)
println(length(line), line)
end
```

##### Use eachindex()[edit]

A common pattern when iterating through arrays is to perform some task for each value of i, where i is the index number of each element, not the element:

```
for i = 1:length(A)
# do something with i or A[i]
end
```

There is a more efficient (i.e. faster in some situations) way to do this:

```
for i in eachindex(A)
# do something with i or A[i]
end
```

#### Even more iterators[edit]

There's a Julia package called Iterators.jl that provides some advanced iterator functions.

```
julia> using Iterators
```

For example, `partition()`

groups the objects in the iterator into easily-handled chunks:

```
julia> for i in partition(1:10, 3, 1)
@show i
end
i = (1,2,3)
i = (2,3,4)
i = (3,4,5)
i = (4,5,6)
i = (5,6,7)
i = (6,7,8)
i = (7,8,9)
i = (8,9,10)
```

`chain()`

works through all the iterators one after the other:

```
julia> for i in chain(1:3, ['a', 'b', 'c'])
@show i
end
i = 1
i = 2
i = 3
i = 'a'
i = 'b'
i = 'c'
```

`subsets()`

works through all subsets of an object. You can specify a size:

```
julia> for i in subsets(collect(1:6), 3)
@show i
end
i = [1,2,3]
i = [1,2,4]
i = [1,2,5]
i = [1,2,6]
i = [1,3,4]
i = [1,3,5]
i = [1,3,6]
i = [1,4,5]
i = [1,4,6]
i = [1,5,6]
i = [2,3,4]
i = [2,3,5]
i = [2,3,6]
i = [2,4,5]
i = [2,4,6]
i = [2,5,6]
i = [3,4,5]
i = [3,4,6]
i = [3,5,6]
i = [4,5,6]
```

#### Making your own iterable objects[edit]

It's possible to design your own iterable objects. What you do is create a new type that has `start()`

, `next()`

, and `done()`

methods. Then, a `for`

.. `end`

loop can work through the components of your object by calling the methods automatically as necessary.

This example shows how you can create an iterable object that iterates through prime numbers, starting at 1.

(The `isprime()`

function lives in an external package called Primes, so before starting this section, you must add it and import it.)

```
julia> Pkg.add("Primes")
julia> using Primes
```

First, you define a new type that will be a prime-iterator:

```
struct PrimeIterator
n::Integer
end
```

You will later create an iterable object of this type using the code:

```
first20primes = PrimeIterator(20)
```

The number you supply is passed to the type constructor, and stored in `n`

. The iterator will be expected to generate every prime up to this number.

Next, you must define three methods that the iteration process will call. First, you want to add a `start()`

method for starting the iteration process off. This function already exists in Julia (that's why you can iterate over all the basic data objects), so the `Base`

prefix is required: you're adding a new method to existing `start()`

function, one which is designed to handle these special objects.

```
function Base.start(::PrimeIterator)
1
end
```

Next, add a `next()`

method to Julia's `next`

function which takes an iterable object and returns a tuple of two values. The first item in the tuple returned, whether returned by the first part of the `if`

clause or the `else`

clause, is the next value of the iterator. The last item is the state that will be preserved and passed on to the next invocation of `next()`

. In this particular case, the code just runs up to find the next prime number above `state`

:

```
function Base.next(::PrimeIterator,state)
if state == 1
return (1, 2) # first return possibility
else
while ! isprime(state)
state += 1
end
(state, state += 1) # second return possibility
end
end
```

Finally, a `done()`

method is required so that the iteration knows when to stop. In this case this is trivial, because the construction of the PrimeIterator object expected a number, which acts as the stop point. This function is the only one which refers to the original number which was passed to the constructor. This number was called `n`

in the type definition, so it can be accessed using the "." field accessor.

```
function Base.done(piter::PrimeIterator, state)
state >= piter.n
end
```

With these three methods defined for the PrimeIterator type, it's now possible to iterate through primes, eg from 1 to 20:

```
first20primes = PrimeIterator(20)
for i in first20primes
println(i)
end
1
2
3
5
7
11
13
17
19
```

As you add more methods that handle PrimeIterator objects, you can use more and more Julia functions with it. For example, if you add a `length`

method:

```
function Base.length(piter::PrimeIterator)
piter.n
end
```

then Julia's `length()`

function knows about PrimeIterators:

```
julia> length(first20primes)
20
```

For some types (but perhaps not so easy for prime numbers), you can add a `getindex()`

method to Julia's `getindex()`

function. This allows you to make use of the array indexing notation to find the **nth** prime.

We'll cheat a bit by using Primes.jl to calculate the primes.

```
function Base.getindex(pi::PrimeIterator, i::Int)
1 <= i < length(pi) || throw(BoundsError(pi, i))
i == 1 && return 1
return primes(pi.n)[i-1]
end
```

This lets us do this:

```
julia> first20primes[1]
1
julia> first20primes[2]
2
julia> first20primes[3]
3
julia> first20primes[8]
17
julia> first20primes[9]
19
```

(Code inspired by Carl Vogel posts at [1].)

#### Nested loops[edit]

If you want to nest one loop inside another, you don't have to duplicate the `for`

and `end`

keywords. Just use a comma:

```
julia> for x in 1:10, y in 1:10
@show (x, y)
end
(x,y) = (1,1)
(x,y) = (1,2)
(x,y) = (1,3)
(x,y) = (1,4)
(x,y) = (1,5)
(x,y) = (1,6)
(x,y) = (1,7)
(x,y) = (1,8)
(x,y) = (1,9)
(x,y) = (1,10)
(x,y) = (2,1)
(x,y) = (2,2)
(x,y) = (2,3)
(x,y) = (2,4)
(x,y) = (2,5)
(x,y) = (2,6)
(x,y) = (2,7)
(x,y) = (2,8)
(x,y) = (2,9)
(x,y) = (2,10)
(x,y) = (3,1)
(x,y) = (3,2)
...
(x,y) = (9,9)
(x,y) = (9,10)
(x,y) = (10,1)
(x,y) = (10,2)
(x,y) = (10,3)
(x,y) = (10,4)
(x,y) = (10,5)
(x,y) = (10,6)
(x,y) = (10,7)
(x,y) = (10,8)
(x,y) = (10,9)
(x,y) = (10,10)
```

(The useful `@show`

macro prints out the names of things and their values.)

One difference between the shorter and longer forms of nesting loops is the behaviour of `break`

:

```
julia> for x in 1:10
for y in 1:10
@show (x, y)
if y % 3 == 0
break
end
end
end
(x,y) = (1,1)
(x,y) = (1,2)
(x,y) = (1,3)
(x,y) = (2,1)
(x,y) = (2,2)
(x,y) = (2,3)
(x,y) = (3,1)
(x,y) = (3,2)
(x,y) = (3,3)
(x,y) = (4,1)
(x,y) = (4,2)
(x,y) = (4,3)
(x,y) = (5,1)
(x,y) = (5,2)
(x,y) = (5,3)
(x,y) = (6,1)
(x,y) = (6,2)
(x,y) = (6,3)
(x,y) = (7,1)
(x,y) = (7,2)
(x,y) = (7,3)
(x,y) = (8,1)
(x,y) = (8,2)
(x,y) = (8,3)
(x,y) = (9,1)
(x,y) = (9,2)
(x,y) = (9,3)
(x,y) = (10,1)
(x,y) = (10,2)
(x,y) = (10,3)
julia> for x in 1:10, y in 1:10
@show (x, y)
if y % 3 == 0
break
end
end
(x,y) = (1,1)
(x,y) = (1,2)
(x,y) = (1,3)
```

Notice that `break`

breaks out of both inner and outer loops in the shorter form, but only out of the inner loop in the longer form.

#### Optimizing nested loops[edit]

With Julia, the inner loop should concern rows rather than columns. This is due to how arrays are stored in memory.

This function is badly written, because it looks at every column of a row, then at every column of the next row, and so on:

```
function laplacian_bad(lap_x::Array{Float64,2}, x::Array{Float64,2})
nr,nc = size(x)
for ir = 2:nr-1, ic = 2:nc-1 # bad loop nesting order
lap_x[ir,ic] =
(x[ir+1,ic] + x[ir-1,ic] +
x[ir,ic+1] + x[ir,ic-1]) - 4*x[ir,ic]
end
end
```

In this version, the two loops are nested properly:

```
function laplacian_good(lap_x::Array{Float64,2}, x::Array{Float64,2})
nr,nc = size(x)
for ic = 2:nc-1, ir = 2:nr-1 # good loop nesting order
lap_x[ir,ic] =
(x[ir+1,ic] + x[ir-1,ic] +
x[ir,ic+1] + x[ir,ic-1]) - 4*x[ir,ic]
end
end
```

Another way to increase the speed is to remove the array bounds checking, using the macro `@inbounds`

:

```
function laplacian_good_nocheck(lap_x::Array{Float64,2}, x::Array{Float64,2})
nr,nc = size(x)
for ic = 2:nc-1, ir = 2:nr-1 # good loop nesting order
@inbounds begin lap_x[ir,ic] = # no array bounds checking
(x[ir+1,ic] + x[ir-1,ic] +
x[ir,ic+1] + x[ir,ic-1]) - 4*x[ir,ic]
end
end
end
```

Here's the test function:

```
function main_test(nr, nc)
field = zeros(nr, nc)
for ic = 1:nc, ir = 1:nr
if ir == 1 || ic == 1 || ir == nr || ic == nc
field[ir,ic] = 1.0
end
end
lap_field = zeros(size(field))
time = @elapsed laplacian_bad(lap_field, field)
@printf "laplacian_bad: %.3f s\n" time
time = @elapsed laplacian_good(lap_field, field)
@printf "laplacian_good: %.3f s\n" time
time = @elapsed laplacian_good_nocheck(lap_field, field)
@printf "laplacian_good_nockeck: %.3f s\n" time
end
```

and the result on a 2012 core-i7 laptop:

julia> main_test(10000,10000) laplace_bad: 3.209 s laplace_good: 0.436 s laplace_good_nockeck: 0.157 s

### While loops[edit]

To repeat some expressions while a condition is true, use the `while`

... `end`

construction.

```
julia> x = 0
0
julia> while x < 4
println(x)
x += 1
end
0
1
2
3
```

If you want the condition to be tested after the statements, rather than before, producing a "do .. until" form, use the following construction:

```
while true
println(x)
x += 1
x >= 4 && break
end
0
1
2
3
```

Here we're using a Boolean switch rather than an `if`

... `end`

statement.

Using Julia's macros, you can create your own control structures. See Metaprogramming.

### Exceptions[edit]

If you want to write code that checks for errors and handles them gracefully, use the `try`

... `catch`

construction.

With a `catch`

phrase, you can handle problems that occur in your code, possibly allowing the program to continue rather than grind to a halt.

In the next example, our code attempts to change the first character of a string directly (which isn't allowed, because strings in Julia can't be modified in place):

```
julia> s = "string";
julia> try
s[1] = "p"
catch e
println("caught an error $e")
println("but we can continue with execution")
end
caught an error <code>MethodError(setindex!,("string","p",1))</code> but we can continue with execution
```

The `error()`

function raises an error exception with a given message.

### Do block[edit]

Finally, let's look at a `do`

block, which is another syntax form that, like the list comprehension, looks at first sight to be a bit backwards (i.e. it can perhaps be better understood by starting at the end and working towards the beginning).

Remember the `find()`

example from earlier?

```
julia> smallprimes = [1,2,3,5,7,11,13,17,19,23];
julia> find(x -> x == 13, smallprimes)
1-element Array{Int64,1}:
7
```

The anonymous function (`x -> x == 13`

) is the first argument of `find()`

, and operates on the second. But with a `do`

block, you can lift the anonymous function out and put it in between a `do ... end`

block construction:

```
julia> find(smallprimes) do x
x == 13
end
1-element Array{Int64,1}:
7
```

You just lose the arrow and change the order, putting the `find()`

function and its target argument first, then adding the anonymous function's arguments and body after the `do`

.

The idea is that it's easier to write a longer anonymous function on multiple lines at the end of the form, rather than wedged in as the first argument.