# Flow Control

In many ways, a computer program is like a journey for your data. Along this journey, data encounters many things that have an impact on it and it is forever changed. Like any journey, one must travel a given path. On that path, there are many roads. Some roads are chosen and others not. Which roads are chosen depends on the end goal.

When you are writing programs, you want your data to make the right decisions. You want your data to do the right thing when it's supposed to. In computer programming, this is called conditional flow.

How do we make data do the right thing? We use conditionals.

## Conditionals

A conditional is a fork (or many forks) in the road. Your data approaches a conditional and the conditional then tells the data where to go based on some defined parameters. Conditionals are formed using a combination of `if` statements and comparison and logical operators `(<, >, <=, >=, ==, !=, &&, ||)`. They are basic logical structures that are defined with the reserved words `if`, `else`, `elsif`, and `end`. Note that `elsif` is missing an "e". Enough talking, time to code.

Create a file called `conditional.rb` and type the following code into it.

``````# conditional.rb

puts "Put in a number"
a = gets.chomp.to_i

if a == 3
puts "a is 3"
elsif a == 4
puts "a is 4"
else
puts "a is neither 3, nor 4"
end
``````

Here we are using `gets` to let the user input a number, `chomp` gets rid of the new line created when the user enters the data, and `to_i` is a method that can be called on a string to turn it into an integer. We need to convert the input into an integer because `gets` always gives us a string.

Run this code three times and do the following:

1. The first time, type in the number 3 and press enter.
2. The second time, type in the number 4 and press enter.
3. The third time, type in any number that isn't 3 or 4 and press enter.

You can repeat the third step more than once to see its effect.

What your code is doing is checking, using the `==` operator you learned previously, to see if the input is equal to the number we have defined. We have effectively controlled the flow of the program by setting conditionals in an `if` statement. Nice work!

The examples below are all valid Ruby conditionals.

``````# Example 1
if x == 3
puts "x is 3"
end

# Example 2
if x == 3
puts "x is 3"
elsif x == 4
puts "x is 4"
end

# Example 3
if x == 3
puts "x is 3"
else
puts "x is NOT 3"
end

# Example 4: must use "then" keyword when using 1-line syntax
if x == 3 then puts "x is 3" end
``````

Last, because Ruby is such an expressive language, it also allows you to append the `if` condition at the very end. Example 1 from above could be rewritten like this:

``````puts "x is 3" if x == 3
``````

Ruby also has a reserved word, `unless`. It acts as the opposite of `if`, so you can use it like this:

``````puts "x is NOT 3" unless x == 3
``````

## Comparisons

Let's go over these comparison operators in a little more depth so you can build some more complicated conditional statements. One thing to remember is that comparison operators always return a boolean value. A boolean value is either `true` or `false`, nothing else. We'll try them out in irb to see how they work as well.

The expressions or values that an operator uses are its operands. In comparisons, the expressions to the left and right of the operator are the operands.

1. `==` - The "is equal to" operator. Anything to the left of the symbol is exactly equal to anything on the right. We talked about this operator earlier in our chapter on variables so it shouldn't be totally foreign.

``````irb :001 > 5 == 5
=> true

irb :002 > 5 == 6
=> false

irb :003 > 'abc' == 'abc'
=> true

irb :004 > 'abc' == 'abcd'
=> false

irb :005 > 'abc' == 'aBc'
=> false

irb :006 > '5' == '5'
=> true

irb :007 > '5' == '6'
=> false

irb :008 > '5' == 5
=> false
``````

Notice that we can compare strings for equality. To be equal, two strings must have the exact same value. The specific value doesn't matter, just that both strings have the same value. If there is any difference at all, the strings are not equal.

We threw that last example in as a reminder that two values must have the same type or they are not equal. Thus, the string `'5'` is not the same as the number `5`. The comparison is thus `false`.

2. `!=` - The "not equal to" operator. Anything to the left of the symbol is not equal to anything to the right.

``````irb :001 > 4 != 5
=> true

irb :002 > 4 != 4
=> false

irb :003 > 4 != 156
=> true

irb :004 > 'abc' != 'def'
=> true

irb :005 > 'abc' != 'aBc'
=> true

irb :006 > '5' != 5
=> true
``````

As with `==`, we can easily compare two values of the same type for inequality and get reasonable results. However, if the two values have different types, the return value is `true`.

3. `<` - The "less than" symbol. Anything to the left of the symbol has a lower value than anything to the right of the symbol.

4. `>` - The "greater than" symbol. Anything to the left of the symbol has a higher value than anything to the right of the symbol.

``````# Example using 'less than' and 'greater than'

irb :001 > 4 < 5
=> true

irb :002 > 4 > 5
=> false

irb :003 > "4" < "5"
=> true

irb :004 > "4" > "5"
=> false

irb :005 > "42" < "402"
=> false

irb :006 > "42" > "402"
=> true

irb :007 > "42" < "420"
=> true

irb :008 > "42" < 420
ArgumentError (comparison of String with 420 failed)

irb :009 > 42 > "420"
ArgumentError (comparison of Integer with String failed)
``````

The examples numbered `005`, `006`, and `007` are especially tricky! Make sure you understand them. When comparing strings, the comparison is character-by-character. Ruby moves from left-to-right in the strings looking for the first character that is different from its counterpart in the other string. Once it finds a character that differs, it compares that character with its counterpart, and makes a decision based on that. If both strings are equal up to the length of the shorter string as in the final example, then the shorter string is considered less than the longer string.

The final two examples show that you can not use `<` and `>` with values of different types. (The same holds true for the `<=` and `>=` operators shown below.)

5. `<=` - The "less than or equal to" symbol. Anything to the left of the symbol is less than or equal to anything on the right.

6. `>=` - the "greater than or equal to" symbol. Anything to the left of the symbol is greater than or equal to anything on the right.

``````irb :001 > 4 <= 5
=> true

irb :002 > 5 >= 5
=> true

irb :003 > 4 >= 5
=> false

irb :004 > 4 >= 3
=> true

irb :005 > 4 >= 4
=> true
``````

Of course, the `<=` and `>=` operators work equally well with strings.

## Combining Expressions

OK, you're starting to get a decent grasp of conditional flow. It is also possible to combine multiple conditional expressions together to create a more specific scenario. We can do this using the `&&` and `||` operators. Let's see what they mean.

1. `&&` - the "and" operator. Expressions to the left and to the right of this operator both have to be true for the entire expression to be evaluated to true.

``````irb :001 > (4 == 4) && (5 == 5)
=> true

irb :002 > (4 == 5) && (5 == 5)
=> false

irb :002 > (4 == 5) && (5 == 6)
=> false
``````
2. `||` - the "or" operator. Either the expression to the left has to be true, or the expression to the right has to be true for the entire expression to be evaluated to true.

``````irb :001 > (4 == 4) || (5 == 5)
=> true

irb :002 > (4 == 5) || (5 == 5)
=> true

irb :002 > (4 == 5) || (5 == 6)
=> false
``````
3. `!` - the "not" operator. When you add this in front of a boolean expression it will change that boolean value to its opposite.

``````irb :001 > !(4 == 4)
=> false
``````

What happens here is Ruby first evaluates what is in the parentheses and then the `!` operator changes it. We know that `4 == 4` would return true. If we say `!true` then that returns false. You can think of `!true` as saying "not true".

`&&` and `||` don't always return `true` or `false`, but they do when they operate on boolean values. A little later in this chapter we'll see what happens when we use `&&` and `||` with non-boolean values.

Note: When you are combining expressions as we are above, it is helpful to use parentheses to group expressions together. This is helpful for readability and also helps the computer more accurately understand your intention. The computer will evaluate parentheses in normal algebraic order.

Ruby follows an order of precedence when deciding how to evaluate multiple expressions. The following is a list of operations from highest order of precedence (top) to lowest (bottom).

1. `<=`, `<`, `>`, `>=` - Comparison
2. `==`, `!=` - Equality
3. `&&` - Logical AND
4. `||` - Logical OR

Knowing this, we can look at the following expression and see how it is evaluated.

``````if x && y || z
# do something
end
``````

First the `x && y` statement will be executed. If that statement is true, then the program will execute the `# do something` code on the next line. If the `x && y` statement is false, then the `z` will be evaluated. If the `z` is true, the code on the next line will be evaluated. If the `z` is false, then the code will exit the `if` statement.

## Ternary Operator

Ruby has a nice option for short and concise conditional `if` statements. The ternary operator is a common Ruby idiom that makes a quick `if/else` statement easy and keeps it all on one line.

The ternary operator uses a combination of the `?` and `:`.

``````# Ternary operator example

irb :001 > true ? "this is true" : "this is not true"
=> "this is true"

irb :001 > false ? "this is true" : "this is not true"
=> "this is not true"
``````

How does this work? You may have inferred that first the computer evaluates what is to the left of the `?`. If the expression to the left of `?` evaluates as true, the code directly to the right of the `?` gets executed. If the code on the left of the `?` evaluates as false, then the code directly to the right of the `:` gets executed.

Ternary operators definitely come in handy as you start to get more familiar with `if` statements. If you feel like you are unsure of how this works, play around with it in irb and test some other cases out. Nothing can create familiarity more quickly than good ol' repeated exposure and experimentation.

### When Should I Use a Ternary Expression?

Ternary expressions should usually be used to select between 2 values, not to choose between two actions. (An action would be something like printing a value or setting a variable to a new value.) The ternary expression's result should almost always be assigned to a variable, passed to a method as an argument, or returned by a method. If you're not doing one of those things, an `if/else` statement is a better choice.

For example, all of the following are good examples of using a ternary expression:

``````foo = hitchhiker ? 42 : 3.1415    # Assign result of ?: to a variable
puts(hitchhiker ? 42 : 3.1415)    # Pass result as argument
return hitchhiker ? 42 : 3.1415    # Return result
``````

However, the following snippets use ternaries that choose between actions, and should be considered inappropriate uses:

``````hitchhiker ? (foo = 42) : (bar = 3.1415) # Setting variables
hitchhiker ? puts(42) : puts(3.1415)      # Printing
``````

In general, all components of a ternary expression should be relatively simple expressions. Aim for readability, not brevity.

## Case Statement

The final conditional flow structure that we want to talk about is called a case statement. A case statement has similar functionality to an `if` statement but with a slightly different interface.

Case statements use the reserved words `case`, `when`, `else`, and `end`. You create one by first defining a case and then evaluating the value of the case and what operation to complete if that case is true. As always, talking about this stuff is much harder than simply observing how the code behaves. Let's create a file called `case_statement.rb` to play with some case statements and see how they work.

``````# case_statement.rb

a = 5

case a
when 5
puts "a is 5"
when 6
puts "a is 6"
else
puts "a is neither 5, nor 6"
end
``````

This example is roughly equivalent to the following `if/elsif/else` statement:

``````# if_statement.rb

a = 5

if a == 5
puts "a is 5"
elsif a == 6
puts "a is 6"
else
puts "a is neither 5, nor 6"
end
``````

The chief differences are that we only need to specify the variable we want to test once (as the argument to `case`) and we don't specify `a ==` on the individual `when` statements.

You can also save the result of a case statement into a variable. Let's refactor the code above to do just that. This way we don't have to write `puts` so many times.

``````# case_statement.rb <-- refactored

a = 5

when 5
"a is 5"
when 6
"a is 6"
else
"a is neither 5, nor 6"
end

``````

There's a second form of the `case` statement that doesn't take an argument:

``````# case_with_no_arg_statement.rb

a = 5

case
when a == 5
puts "a is 5"
when a == 6
puts "a is 6"
else
puts "a is neither 5, nor 6"
end
``````

The difference here is that we don't provide an argument on line 5, and we have to fully test each value with `a ==`; most developers prefer to use `if/elsif/else/end` instead, but there are situations where this form is preferred. We won't get into that here.

As you can see, there are lots of uses for `case` statements and they can be very powerful tools when writing Ruby programs. Remember, if you're uncomfortable with these, spend some time modifying them and watching how they respond to the changes you make. Test their boundaries to see what they are capable of. Curiosity will serve you well in your journey to learning Ruby. There is much to discover!

## True and False

Notice that after `if` and `elsif` we have to put an expression that evaluates as either true or false. In Ruby, you could even write code like this:

``````a = 5
if a
puts "how can this be true?"
else
puts "it is not true"
end
``````

The output is "how can this be true?". In Ruby, every expression evaluates as true when used in flow control, except for `false` and `nil`. Try the code above and give `a` values of 0, ""(empty string) and even the string 'false' to see the result yourself!

Because of this, we could even write code like this:

``````if x = 5
puts "how can this be true?"
else
puts "it is not true"
end
``````

The above code is not testing whether `x` is equal to "5". It's assigning the variable `x` the value of "5", which will always evaluate to `true`. Unfortunately, that looks very similar to `if x == 5`, which is testing whether `x` is equal to "5". Be careful when reading or writing Ruby; its expressiveness can also be a source of many subtle bugs.

The `&&` and `||` logical operators, as you'll recall, use short-circuit evaluation. These operators work with truthy and falsy values too, and they can also return truthy values instead of boolean values. When using `&&` and `||`, the return value is always the value of the operand evaluated last:

``````irb :001 > 3 || 'foo'     # last evaluated operand is 3
=> 3

irb :002 > 'foo' || 3     # last evaluated operand is 'foo'
=> 'foo'

irb :003 > nil || 'foo'   # last evaluated operand is 'foo'
=> 'foo'

irb :004 > nil && 'foo'   # last evaluated operand is nil
=> nil

irb :005 > 3 && 'foo'     # last evaluated operand is 'foo'
=> 'foo'

irb :006 > 'foo' && 3     # last evaluated operand is 3
=> 3
``````

Suppose you have an expression of some kind that returns a value that is either truthy or falsy, but isn't a boolean value:

``````foo = nil
bar = 'qux'
is_ok = foo || bar
``````

In this code, `is_ok` gets set to a truthy value of `"qux"`. In most cases, you can use `"qux"` as though it were actually a boolean `true` value. However, using a string value as though it is a boolean isn't the clearest way to write your code. It may even look like a mistake to another programmer who is trying to track down a bug. In some strange cases, it may even be a mistake.

You can address this easily enough by using an `if` statement or a ternary expression:

``````is_ok = (foo || bar) ? true : false
``````
``````is_ok
if (foo || bar)
is_ok = true;
else
is_ok = false;
end
``````

Either of those snippets sets `is_ok` to an appropriate boolean value. However, they do so in a somewhat wordy manner. Many JavaScript programmers use a more concise coercion by using what looks like a `!!` operator:

``````is_ok = !!(foo || bar)
``````

In reality, `!!` isn't a separate operator in Ruby Instead, it's two consecutive `!` operators. The expression `!!a` is equivalent to writing `!(!a)`. The inner `!` converts the value of `a` to `false` if it is truthy, or `true` if `a` is falsy. The outer `!` then flips `true` to `false` or `false` to `true`. In the end, we end up with a boolean value instead of a truthiness value:

``````irb :001 !!3    # 3 is truthy, !3 is false, !false is true
=> true

irb :002 !!nil   # nil is falsy, !nil is true, !true is false
=> false
``````

## Summary

This chapter covered booleans, comparisons and the ability to control the flow of code execution with conditionals. These are some of the fundamental tools that you'll carry with you as a Ruby developer. We've got more exercises to drill these skills into your head and fingers!

## Exercises

1. Write down whether the following expressions return `true` or `false`. Then type the expressions into `irb` to see the results.

``````(32 * 4) >= 129
false != !true
true == 4
false == (847 == '847')
(!true || (!(100 / 5) == 20) || ((328 / 4) == 82)) || false
``````

#### Solution

1. false
2. false
3. false
4. true
5. true

Video Walkthrough

2. Write a method that takes a string as an argument. The method should return a new, all-caps version of the string, only if the string is longer than 10 characters. Example: change "hello world" to "HELLO WORLD". (Hint: Ruby's String class has a few methods that would be helpful. Check the Ruby Docs!)

#### Solution

``````# caps_method.rb

def caps(string)
if string.length > 10
string.upcase
else
string
end
end

puts caps("Joe Smith")
puts caps("Joe Robertson")
``````

Video Walkthrough

3. Write a program that takes a number from the user between 0 and 100 and reports back whether the number is between 0 and 50, 51 and 100, or above 100.

#### Solution

``````# evaluate_num.rb

puts "Please enter a number between 0 and 100."
number = gets.chomp.to_i

if number < 0
puts "You can't enter a negative number!"
elsif number <= 50
puts "#{number} is between 0 and 50"
elsif number <= 100
puts "#{number} is between 51 and 100"
else
puts "#{number} is above 100"
end
``````

Video Walkthrough

4. What will each block of code below print to the screen? Write your answer on a piece of paper or in a text editor and then run each block of code to see if you were correct.

``````# Snippet 1
'4' == 4 ? puts("TRUE") : puts("FALSE")
``````
``````# Snippet 2
x = 2
if ((x * 3) / 2) == (4 + 4 - x - 3)
puts "Did you get it right?"
else
puts "Did you?"
end
``````
``````# Snippet 3
y = 9
x = 10
if (x + 1) <= (y)
puts "Alright."
elsif (x + 1) >= (y)
puts "Alright now!"
elsif (y + 1) == x
puts "ALRIGHT NOW!"
else
puts "Alrighty!"
end
``````

#### Solution

1. `"FALSE"`
2. `"Did you get it right?"`
3. `"Alright now!"`

Video Walkthrough

5. When you run the following code...

``````def equal_to_four(x)
if x == 4
puts "yup"
else
puts "nope"
end

equal_to_four(5)
``````

You get the following error message..

``````exercise.rb:8: syntax error, unexpected end-of-input, expecting keyword_end
``````

Why do you get this error and how can you fix it?

#### Solution

You get this error because the `end` in the code above gets matched with the `if..else` statement. The error message is telling us that the interpreter was expecting the keyword `end` to close off our `equal_to_four` method, that `end` was not found.

Video Walkthrough

6. Write down whether the following expressions return `true` or `false` or raise an error. Then, type the expressions into `irb` to see the results.

``````(32 * 4) >= "129"
847 == '847'
'847' < '846'
'847' > '846'
'847' > '8478'
'847' < '8478'
``````

#### Solution

1. Raises an error
2. false
3. false
4. true
5. false
6. true