**Concepts** - After completing this lesson, students will be able to:

Distinguish fruitful functions from void functions

Recognize boolean values and conditional statements

Recognize errors resulting resulting from functions expecting boolean values

**Skills** - After completing this lesson, students will be able to:

Write boolean functions to check the properties of numerical values

Use alternative evaluation execute different funuctions depending on input

Recognize recursive functions, and identify situations in which they might be useful

**Tasks** - This lesson is complete when students have:

Read Chapter: 5 from

*Think Julia*Read Chapter: 6 from

*Think Julia*Completed Assignment03

Run all code examples from Lesson 4 on their own computers

We can build some useful functions with only the components we've discussed so far, but they would be somewhat limited. Let's work on expanding our repertoire with conditional execution, loops, and recursion.

The following sections assume that you have read chapter 5 and chapter 6 in *Think Julia*. You can do chapter 4 if you like (it lets you play with 🐢's - it's fun!), but that's not required for now.

All computers are build on boolean (true/false) logic. At it's core, the two compoents of computer programs (data and actions) are composed from "bits", which are physical objects that can have 2 states (`0`

or `1`

, `off`

or `on`

, `false`

or `true`

), and logical operators.

But we don't need to understand the all the details of how this works at a low-level (I certainly don't) to effectively use boolean operations in our code. There are a couple of things to keep in mind.

As you read in *Think Julia*, you can use conditional evalutation (`if`

block) to execute different code under different circumstances.

```
julia> function complement(base)
if base == 'A'
return 'T'
elseif base == 'T'
return 'A'
else
error("Base $base not supported")
end
end
complement (generic function with 1 method)
julia> complement('A')
'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
```

```
julia> complement('G')
ERROR: Base G not supported
Stacktrace:
#...
```

Tip

Notice that we can use variables to insert values in strings using "interpolation" with `$`

```
julia> mystr = "hello";
julia> myint = 4;
julia> "Well, $mystr there. 2 + 2 is $myint"
"Well, hello there. 2 + 2 is 4"
```

Any arbitrary expression can be interpolated, though in many cases you'll need parentheses:

```
julia> "2+2 is $(2+2)"
"2+2 is 4"
```

If you want to include an actual `$`

sign in a string, you must "escape" it with `\`

, or use a "raw" string:

```
julia> println("That will be \$2.50")
That will be $2.50
julia> println(raw"But I don't have $2.50!'")
But I don't have $2.50!'
```

Here, we're trying to make a function that returns the `complement`

of a DNA base - that is, the base that would be on the opposite strand.

I've entered the complementary bases for `A`

and `T`

, but we're missing `C`

and `G`

.

Practice

Define the `complement()`

function so that it gives the complement of `'G'`

and `'C'`

*in addition to* `'A'`

and `'T'`

.

Be sure to use single quotes - the reason will become clear shortly.

In many cases, we want to test the truth of multiple statements at once. Combining boolean values has rules and precedence, and it's possible to string many of them together.

If your statements get too long, it can be challenging to reason about them. For example, what's the truth of the following statement? (remember, `||`

means "or" and `&&`

means "and"):

`true && false || true && true`

You might figure it out, but personally, my head hurts. In my experience, though, I am typically only comparing two things, so the rules are easy, or I'm using the same logic opperators throughout (all `&&`

or all `||`

).

```
julia> function basetype(base)
if base == 'A' || base == 'G'
println("That's a purine!")
elseif base == 'T' || base == 'C'
println("That's a pyrimidine!")
else
error("Base $base not supported")
end
end
basetype (generic function with 1 method)
julia> basetype('C')
That's a pyrimidine!
```

Another, likely less obvious place where combinatorial logic is at play is in the behavior of `elseif`

. It's important to remember that the first statement in a conditional block that evaluates to `true`

will be executed, and nothing else will. For example,

```
julia> function oddhalf(num)
if iseven(num)
println("That's an even number, you should get an Int, but you won't.")
elseif num == 42
println("Life, the Universe, and Everything!")
else
println("That's an odd number, expect a Float!")
end
return num / 2
end
oddhalf (generic function with 1 method)
julia> oddhalf(42)
That's an even number, you should get an Int, but you won't.
21.0
```

Here, there's no way for `elseif num == 42`

to ever be true, since when `num`

is 42, the `iseven(num)`

gets hit first, and that part of the block is evaluated.

Note

The julia logic operators `&&`

and `||`

are "short circuiting", which means that if the answer can be known before the right-hand side is evaluated, then the right-hand side **won't** be evaluated. This feature can be used to introduce a more concise conditional evaluation than an `if`

block.

For example,

```
julia> function verbosehalf(x)
iseven(x) && println("That's an even number!")
iseven(x) || println("That's an odd number!")
x / 2
end
verbosehalf (generic function with 1 method)
julia> verbosehalf(42)
That's an even number!
21.0
julia> verbosehalf(43)
That's an odd number!
21.5
```

When `43`

is passed as an argument, `iseven(x)`

evaluates to `false`

. And because `false && <anything>`

is always false, that line just evaluates to false without ever getting to the `println()`

call. But `false || <anything>`

depends on the right hand statement (`false || true`

is different than `false || false`

), the right hand statement must be evaluated.

In this case, those lines are equivalent to

```
if iseven(x)
println("That's an even number!")
else
println("That's an odd number!")
end
```

But be aware, chaining these short-circuit expressions is NOT like `if/elseif/else`

since, regardless of the outcome of the expression, the following lines *are* evaluated. Eg, if I try to write the `oddhalf()`

function from above like this:

```
julia> function oddhalf(num)
iseven(num) && println("That's an even number, you should get an Int, but you won't.")
num == 42 && println("Life, the Universe, and Everything!")
println("That's an odd number, expect a Float!")
return num / 2
end
oddhalf (generic function with 1 method)
julia> oddhalf(42)
That's an even number, you should get an Int, but you won't.
Life, the Universe, and Everything!
That's an odd number, expect a Float!
21.0
```

Not exactly what we wanted...

"Checking Questions"

Referring back to our

`complement`

function, What happens if you try to pass`"G"`

as an argument (note the double quotes)? Can you explain this behavior?Evaluate

`'G' == "G"`

- did you expect it to be`true`

or`false`

?What are the types of

`'G'`

and`"G"`

?Use the

`||`

operator to modify the`if`

/`elseif`

statements in your`complement()`

function) from above so that it works with either single-quoted or double-quoted ACGT.**Note:**you should have no more than 3`elseif`

s in your function, and you should always return a single-quoted version of the complement.

I find recursion difficult to wrap my head around. To be honest, I almost told you skip those sections of chapters 5 and 6. But I think it is valuable to encounter the concept so that you know it exists, even if we don't explore the concept in great detail.

In the years I've been programming, I think I've only written 2 recursive functions. But there are areas of biology where they can be quite valuable, and actually easier to understand, especially those involving phylogenetic trees or other graph structures, such as those used in genome assembly.

In these cases, we often want to perform and action on a node, and all the children of that node, which are also nodes, also with children... and so on. In fact, this is similar to how many shell programs interact with your file system (which is also like a tree).

But beyond noting that it has its uses, we won't spend much time on recursive functions in this course.

© Kevin Bonham, PhD. Last modified: August 18, 2021. Website built with Franklin.jl and the Julia programming language.