Programming Fundamentals - Part 2 - Conditionals

In the last section, we learned about the basic data types - specifically, Integers and Strings.  There is another basic data type that is critical to every programming language - the Boolean.

A Boolean - true or false - is used to conditionally change the behavior and output of some code depending on the boolean's value (i.e. is it true or false).  Here are some examples:

  • Is my bank account balance greater than $50?  If yes, let me withdraw $50; if no, do not let me withdraw $50 and display an error message.
  • When logging in to Twitter, does the password I entered match my account's password?  If yes, log me into my account and let me post a tweet; if no, ask me to attempt to login again.

These kinds of questions generally get yes/no responses.  But if we rephrased them as statements, we can determine if they are true or false:

  • Statement: My bank account balance is greater than $50.
    Reality: My bank account balance is $51.  This statement is true.
  • Statement: When logging in to Twitter, the password I entered is the same as my account's password.
    Reality: I entered "tacos" which is not the real password for this account.  This statement is false.

Similarly, in software, we write an expression in code that can be evaluated as being either true or false and then follow the appropriate branch of logic.

If you haven't already done so, go to this lesson's repository and open it in Gitpod.  Then, in the code-along directory, open the file 2-conditionals.rb.

Under the # Booleans comment, let's create a boolean variable:

# Booleans
test_is_true = true
puts test_is_true

test_is_false = false
puts test_is_false

This is a trivial example since we're explicitly defining the boolean value.  In reality, we want to ask or evaluate if a statement is true/false.  To do so, we need comparison operators – operators that compare two values and return a boolean value as a result. There are several of these comparison operators, but the important ones (for now) are as follows:

Operator Name Description
== Equal Returns true if the operands are equal.
!= Not equal Returns true if the operands are not equal.
> Greater than Returns true if the left operand is greater than the right operand.
>= Greater than or equal Returns true if the left operand is greater than or equal to the right operand.
< Less than Returns true if the left operand is less than the right operand.
<= Less than or equal Returns true if the left operand is less than or equal to the right operand.

Using these operators, we can write boolean expressions:

puts 3 == 2 # returns false
puts 3 != 2 # returns true
puts 3 > 2 # returns true
puts 3 < 2 # returns false

And now we can write code that will only execute if a boolean expression is true.  The basic structure is:

if 3 == 2
  puts "This text should never be displayed"
end

if 3 > 2
  puts "This text should always be displayed"
end

We can also specify what should happen when the comparison provided in the if statement evaluates to false using the else keyword:

if 3 == 2
  puts "This text should never be displayed"
else
  puts "3 does not equal 2, so this is the false logic branch"
end

These examples are obviously trivial - there's no need to write code to handle the condition when 3 == 2 since that will never be true.  So let's try to write logic representing the more real-world examples from above:

user_entered_password = "tacos"
real_password = "secret"
if user_entered_password == real_password
  puts "Your password matches.  You are now logged in!"
else
  puts "Wrong password.  Try again."
end

bank_account_balance = 51
if bank_account_balance > 50
  bank_account_balance = bank_account_balance - 50
  puts "You have successfully withdrawn $50"
else
  puts "Insufficient funds for that transaction."
end

Sometimes our code needs to handle more than 2 possible outcomes.  For example, in a soccer (aka football) match, your team might win, lose, or tie depending on the final score.  In ruby, to handle an alternative condition, we can use elsif:

your_team_score = 2
other_team_score = 2
if your_team_score > other_team_score
  puts "Yay, your team won!"
elsif your_team_score == other_team_score
  puts "Ok, you tied ¯\_(ツ)_/¯"
else
  puts "Your team lost :("
end

Note that in the above logic, the final condition could have been written with another elsif: elsif your_team_score < other_team_score.  But since that's the only remaining option, it's unnecessary.

We can also combine these comparison operators with logical operators to create more in-depth conditions.  Those operators are:

Operator Name Description
&& And Returns true if the expressions are both true.
|| Or Returns true if either the left expression or right expression is true.

Some logic in a weather application might look like this:

temp = 68
precipitation = 0
if temp >= 65 && temp <= 75 && precipitation == 0
  puts "It's perfect outside!"
end

The Thing You'll Get Wrong 99 Times Until You Finally Get It Right

The single equals sign (=) is used for variable assignment.  The double equals sign (==) is used for comparing equality.  Don't confuse the two!  Consider the following code:

dinner = "kale"
      
# incorrect - will cause unexpected results!
if dinner = "tacos"
  # This will always be true. The variable's value is reassigned.
end
      
# correct
if dinner == "tacos"
  # This will properly perform the comparison
end

The code in the first example dinner = "tacos" will always be true. Why? Because we're not performing a comparison; instead we're assigning the value of "tacos" to the variable dinner – and this will always successfully complete.

Lab

Time for a lab to practice conditional logic. Instructions are in the file 2-conditionals.rb in the labs directory.