Ruby

Conditional Logic

Ruby Course

Introduction

This lesson is all about controlling the flow of your code. When you have some code that you only want to execute under specific conditions, you will need a way for the computer to check whether those conditions have been met. Conditional logic can be found everywhere in everyday life. Ever had to tidy your room before being allowed to play video games? That’s your mother setting up a nice conditional statement that might look like this in a computer program…

if room_tidy == true
  "I can play video games"
end

There must be a motherboard joke in there somewhere. Answers on a postcard!

Any conditional statement will always have an expression that evaluates to true or false. Based on this answer, the computer will decide whether or not to execute the code that follows. If it’s true, then the code will be processed; if it’s false, the code will be skipped, and you can provide some other code that will be run instead. There can even be several conditional statements on one line, but keep in mind that too many can make code look cluttered.

You’ll write a lot of conditional statements on your road to programmer stardom. Although they are fundamentally simple, they are a big source of bugs in your code when something isn’t working as expected. Make sure you understand the logic behind the expression being evaluated so you can step through it if you need to.

Lesson overview

This section contains a general overview of topics that you will learn in this lesson.

  • Describe and list falsy values.
  • Explain how to use if, elsif, and else.
  • Explain the difference between if and unless.
  • Describe what ||, &&, and ! do.
  • Explain what short circuit evaluation is.
  • Describe what the ternary operator is and how to use it.
  • Explain what a case statement is and how it works.

Truthy and falsy in Ruby

You already know that conditional statements check expressions for a true or false value, so it follows that you need to understand what Ruby considers to be true or false. In typical Ruby fashion, it’s very simple. The only false values in Ruby are the values nil and false themselves. That’s it! Everything else is considered true. Even the string "false" is true in conditional expressions! If you have experience with other programming languages, you might be familiar with the number 0 or an empty string (“”) being equivalent to false. This isn’t the case with Ruby, so be careful when writing those expressions. Otherwise, you might end up with more bugs on your screen than if you were using light mode at midnight.

Basic conditional statement

The simplest way to control the flow of your code using conditionals is with the if statement.

The general syntax of an if statement is shown here:

if statement_to_be_evaluated == true
  # do something awesome...
end

if 1 < 2
  puts "Hot diggity, 1 is less than 2!"
end
#=> Hot diggity, 1 is less than 2!

If there is only one line of code to be evaluated inside the block, then you can rewrite the code to be more succinct and take up only one line:

puts "Hot diggity damn, 1 is less than 2" if 1 < 2

You don’t even need the end statement. Nice and concise!

The statement to be evaluated can be anything that returns true or false. It could be a mathematical expression, a variable value, or a call to a method. Only if the expression evaluates to true does the code inside the block run.

Adding else and elsif

We often want to check a condition and run some code if it’s true but then run some other code if it’s false. This is done with an if...else statement.

if attack_by_land == true
  puts "release the goat"
else
  puts "release the shark"
end

Oh yeah! Protected on land and sea.

But what about if we’re attacked by air? We need yet another conditional check. Enter the if...elsif...else statement!

if attack_by_land == true
  puts "release the goat"
elsif attack_by_sea == true
  puts "release the shark"
else
  puts "release Kevin the octopus"
end

Ain’t nobody pillaging our land!

You can have as many elsif expressions as you want. The else clause is optional, but you usually want to provide some default value in case none of the previous expressions evaluate to true.

Boolean logic

To determine whether an expression evaluates to true or false, you’ll need a comparison operator. There are several provided by Ruby:

== (equals) returns true if the values compared are equal.

5 == 5 #=> true
5 == 6 #=> false

!= (not equal) returns true if the values compared are not equal.

5 != 7 #=> true
5 != 5 #=> false

> (greater than) returns true if the value on the left of the operator is larger than the value on the right.

7 > 5 #=> true
5 > 7 #=> false

< (less than) returns true if the value on the left of the operator is smaller than the value on the right.

5 < 7 #=> true
7 < 5 #=> false

>= (greater than or equal to) returns true if the value on the left of the operator is larger than or equal to the value on the right.

7 >= 7 #=> true
7 >= 5 #=> true

<= (less than or equal to) returns true if the value on the left of the operator is smaller than or equal to the value on the right.

5 <= 5 #=> true
5 <= 7 #=> true

#eql? checks both the value type and the actual value it holds.

5.eql?(5.0) #=> false; although they are the same value, one is an integer and the other is a float
5.eql?(5)   #=> true

#equal? checks whether both values are the exact same object in memory. This can be slightly confusing because of the way computers store some values for efficiency. Two variables pointing to the same number will usually return true.

a = 5
b = 5
a.equal?(b) #=> true

This expression is true because of the way computers store integers in memory. Although two different variables are holding the number 5, they point to the same object in memory. However, consider the next code example:

a = "hello"
b = "hello"
a.equal?(b) #=> false

This happens because computers can’t store strings in the same efficient way they store numbers. Although the values of the variables are the same, the computer has created two separate string objects in memory.

In addition to the above operators, Ruby has a special operator that is affectionately referred to as the spaceship operator. Unlike the other comparison operators, which all return true or false, the spaceship operator returns one of three numerical values.

<=> (spaceship operator) returns the following:

  • -1 if the value on the left is less than the value on the right;
  • 0 if the value on the left is equal to the value on the right; and
  • 1 if the value on the left is greater than the value on the right.
5 <=> 10    #=> -1
10 <=> 10   #=> 0
10 <=> 5    #=> 1

The spaceship operator is most commonly used in sorting functions, which we’ll cover more later.

All of the above operators also work on data types other than numbers, such as strings. Why not play around with this in a REPL?

Logical operators

Sometimes you’ll want to write an expression that contains more than one condition. In Ruby, this is accomplished with logical operators, which are && (and), || (or) and ! (not).

There are some differences between the word versions and their symbolic equivalents, particularly in the way they evaluate code. We recommend you watch this video that explains the differences between symbolic logical operators and their word versions.

The && operator returns true if both the left and right expressions return true.

if 1 < 2 && 5 < 6
  puts "Party at Kevin's!"
end

# This can also be written as
if 1 < 2 and 5 < 6
  puts "Party at Kevin's!"
end

One thing to keep in mind with the && and || operators is the order of logic. The expressions are always evaluated from left to right.

Using the && operator, both expressions must return true. If the first expression encountered returns false, then the second expression is never checked. To the Ruby interpreter, it’s pointless to evaluate the second half as the overall expression can never return true.

With the || operator, if the first expression evaluates to true, then the second expression is never checked because the complete expression is already true, and the code in the block is run.

This is known as short circuit evaluation.

if 10 < 2 || 5 < 6 #=> although the left expression is false, there is a party at Kevin's because the right expression returns true
  puts "Party at Kevin's!"
end

# This can also be written as
if 10 < 2 or 5 < 6
  puts "Party at Kevin's!"
end

The ! operator reverses the logic of the expression. Therefore, if the expression itself returns false, using the ! operator makes the expression true, and the code inside the block will be executed.

if !false     #=> true

if !(10 < 5)  #=> true

Case statements

Case statements are a neat way of writing several conditional expressions that would normally result in a messy if...elsif statement. You can even assign the return value from a case statement to a variable for use later.

Case statements process each condition in turn, and if the condition returns false, it will move onto the next one until a match is found. An else clause can be provided to serve as a default if no match is found.

grade = 'F'

did_i_pass = case grade #=> create a variable `did_i_pass` and assign the result of a call to case with the variable grade passed in
  when 'A' then "Hell yeah!"
  when 'D' then "Don't tell your mother."
  else "'YOU SHALL NOT PASS!' -Gandalf"
end

As soon as a match is found, the value of that match is returned, and the case statement stops execution. Can you tell what the value of the did_i_pass variable is going to be after the case statement?

If you need to do some more complex code manipulation, you can remove the then keyword and instead place the code to be executed on the next line.

grade = 'F'

case grade
when 'A'
  puts "You're a genius"
  future_bank_account_balance = 5_000_000
when 'D'
  puts "Better luck next time"
  can_i_retire_soon = false
else
  puts "'YOU SHALL NOT PASS!' -Gandalf"
  fml = true
end

Unless statements

An unless statement works in the opposite way as an if statement: it only processes the code in the block if the expression evaluates to false. There isn’t much more to it.

age = 19
unless age < 18
  puts "Get a job."
end

Just like with if statements, you can write an unless statement on one line, and you can also add an else clause.

age = 19
puts "Welcome to a life of debt." unless age < 18

unless age < 18
  puts "Down with that sort of thing."
else
  puts "Careful now!"
end

You should use an unless statement when you want to not do something if a condition is true, because it can make your code more readable than using if !true.

Ternary operator

The ternary operator is a one-line if...else statement that can make your code much more concise.

Its syntax is conditional statement ? <execute if true> : <execute if false>. You can assign the return value of the expression to a variable.

age = 19
response = age < 18 ? "You still have your entire life ahead of you." : "You're all grown up."
puts response #=> "You're all grown up."

Here, because the expression evaluated to false, the code after the : was assigned to the variable response.

Writing this as an if...else statement would be much more verbose:

age = 19
if age < 18
  response = "You still have your entire life ahead of you."
else
  response = "You're all grown up."
end

puts response #=> "You're all grown up."

However, if your conditional statements are complicated, then using an if...else statement can help to make your code more readable. Remember, above all else, your code needs to be readable and understandable by other people, especially in the development stage. You can always optimize your code for efficiency once it’s finished and you’re moving to a production environment where speed matters.

Assignment

  1. For more depth, read the Flow Control chapter from LaunchSchool’s Introduction to Programming With Ruby.
  2. For an overview of flow control, read through this Ruby Explained: Conditionals and Flow Control article.

Knowledge check

The following questions are an opportunity to reflect on key topics in this lesson. If you can’t answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge.

Additional resources

This section contains helpful links to related content. It isn’t required, so consider it supplemental.

Support us!

The Odin Project is funded by the community. Join us in empowering learners around the globe by supporting The Odin Project!