Boolean Logic
Learning Goals
- explain “falsy” vs “truthy”
- apply the key logic operators AND, OR, and NOT
- combine operations into a logic expression
- utilize a truth table to illustrate a logical expression
- trace multiple paths through a code snippet
- apply compound logic to flatten nested
if
statements
Vocabulary
- Boolean
- Truthy
- Falsey
- Precedence
- Truth Table
- Flow Control
WarmUp
First, start by doing some research. You may choose independent or paired.
Truthy and falsy
- What do you think it means to describe something as ‘truthy’?
- What about ‘falsy’?
Truthy and falsy values in Ruby
- How many falsey values are there in Ruby?
- What is truthy in Ruby?
When you’ve answered the questions above, which of these are truthy and which are falsey?
#pry
if value_to_check
puts "I'm truthy!"
end
Values to Check:
- 1.0
- “hello”
- nil
- 0
- false
- true
- “false”
What about Truthy and Falsy in JS?
In JavaScript, all values are truthy except
false
, 0
, -0
, null
, undefined
, NaN
, and document.all
.
Why?
Why is it helpful to have a working understanding of boolean logic? It can help us flatten if
statements and reduce the number of lines in our code. We are also going to encounter this frequently in our jobs. A lack in understanding can introduce bugs into our code bases.
AND/OR/NOT and Truth Tables
A truth table is a mathematical table used in logic. In the truth table below the first two columns (a
and b
) are our input variables. Our table should cover all of the different possible combinations of input variables. There are four different combinations for our two input variables (a
and b
). These are represented as rows. The remaining columns show all of the possible results of three Ruby operators for a given row. So the first row says if a
is true
and b
is true
then a && b
is true
, a || b
is true
, and !a
is false
.
Independent Practice
Use a pry
session to clarify how these three Ruby operators work. For each row, set a
and b
to their values and experiment with the Ruby operators.
Example:
[1] pry(main)> a = true
=> true
[2] pry(main)> b = true
=> true
[3] pry(main)> a && b
=> true
a |
b |
a && b |
a || b |
!a |
---|---|---|---|---|
true | true | true | true | false |
true | false | |||
false | true | |||
false | false |
a |
b |
a && b |
a || b |
!a |
---|---|---|---|---|
true | true | true | true | false |
true | false | false | true | false |
false | true | false | true | true |
false | false | false | false | true |
Expressions and Precedence with Parentheses
Let’s pop a few scenarios into pry, pause before hitting ‘enter’:
Agree/Disagree
What do you expect it to return? true
? false
? Why?
false && false || true
Precedence
It depends on the order Ruby executes. Precedence refers to the order of opperations which Ruby follows. Here are a few you probably use regularly. The list is read top down in order of precedence.
!
>, >=, <, <=
<=>, ==, ===, !=, =~, !~
&&
||
=, +=, -=, etc.
Ruby will run comparisions in order or precedence, if there are multiple of the same operator they will be evaluated starting with the left most operator.
If we take this Boolean Expression, false || true && false || false
, we can diagram the order Ruby will evaluate it in.
false || true && false || false
\ /
false || false || false
false
What if you want the order Ruby executes this in to be different from its default? Enter, parens ().
Let’s revisit that last expressions in pry
, but let’s add some parentheses.
false && false || true
false && (false || true)
Expressions in JavaScript
These expressions will also work in JavaScript:
function determineTruthyness(expression) {
if (expression) {
return `The expression ${expression} is true!`
} else {
return `The expression ${expression} is false!`
}
}
var exp_1 = false && false || true
var exp_2 = false && (false || true)
determineTruthyness(exp_1);
determineTruthyness(exp_2);
Turn & Talk Turn to your neighbor and discuss what order you believe Ruby is evaluating each boolean expression in. What will the result be?
Paired Practice
Complex Truth Tables
Evaluate the following by creating a truth table for three boolean values (A
, B
, and C
) and using it to solve the following expressions:
(A || B) && (A || C)
(A || !B) || (!A || C)
((A && B) && C) || (B && !A)
((A && B) && !C) || ((A && C) && !B)
Independent Practice
By yourself or with a partner:
- Clone the Boolean Logic Practice Repo onto your local machine
- cd vehicle_boolean
- rspec spec/vehicle_analysis_spec.rb (make sure all tests start out passing)
- You may need to
gem install stringio
and/orgem install o_stream_catcher
- You may need to
- Complete Activity 1 and Activity 2 (see below)
Activity 1: Vehicle
# vehicle.rb
class Vehicle
attr_reader :model, :four_wheel, :big_back_wheels
def initialize(model, four_wheel, big_back_wheels)
@model = model
@four_wheel = four_wheel
@big_back_wheels = big_back_wheels
end
def car?
model == "car"
end
def tractor?
model == "tractor"
end
def pickup?
model == "pickup"
end
def four_wheel_drive?
four_wheel
end
def big_back_wheels?
big_back_wheels
end
end
# vehicle_analysis.rb
class VehicleAnalysis
def analyze(vehicle)
if vehicle.car?
if vehicle.four_wheel_drive? || !vehicle.four_wheel_drive?
puts "Vehicle has four wheels "
if vehicle.four_wheel_drive?
puts "with four wheel drive"
else
puts "with two wheel drive"
end
end
elsif vehicle.tractor?
puts "Vehicle has four wheels "
if vehicle.big_back_wheels?
puts "with big wheels in the back"
end
elsif vehicle.pickup?
puts "Vehicle has four wheels "
if vehicle.four_wheel_drive?
puts "with four wheel drive"
else
puts "with two wheel drive"
end
if vehicle.big_back_wheels?
puts "with big wheels in the back"
end
end
end
end
# analysis_runner.rb
require "vehicle"
require "vehicle_analysis"
vehicle = Vehicle.new("pickup", true, true)
VehicleAnalysis.new.analyze(vehicle)
- How many unique execution paths are there through the block of code starting with
if vehicle.car?
statement? - Chart out the conditions which would lead to these paths consider using a truth table.
Activity 2: Flattening if
statements
Take the code from the previous exercise. Let’s try to refactor it. Start by flattening it down. Can you simplify the logic to reduce the number of paths? How few can you get it down to? Compare your results with a peer.
Convert the nested if/else statements to flatter boolean expressions.
Wrapup
- What objects are truthy in Ruby? What objects are falsey?
- What are the rules of precedence for Boolean expressions in Ruby?
- Why might you use complex Boolean expressions?