Booleans and nil
Bean Cart's script checks if cups_left to decide whether to take another order. With 0 cups left, it still says yes. A programmer from Python or JavaScript expects 0 to count as "false", but Ruby has a much shorter list of false things, and that list is worth memorising.
The rule
Only
falseandnilare falsy; everything else is truthy.
Ruby's booleans are the two objects true and false. They belong to the classes TrueClass and FalseClass; there is no single Boolean class.
nil means "no value here". It is the only object of class NilClass. You get it when something is missing:
MENU = { latte: 4.50 }
MENU[:chai] # => nil (no such key)
[1, 2][5] # => nil (no such index)
puts "hi" # returns nilIn a condition, Ruby does not need a real boolean. It only asks: "is this false or nil?" If not, the condition passes. So all of these are truthy: 0, "", [], {}, "false", 0.0.
cups_left = 0
if cups_left
puts "Take order" # this runs: 0 is truthy
end
if cups_left > 0 # the real question
puts "Take order"
endTo test for nil specifically, ask the object: price.nil?. To test for "empty", ask that instead: name.empty?, orders.empty?, cups_left.zero?.
nil has safe conversions that come up often: nil.to_s is "", nil.to_a is [], and nil.to_i is 0. And the safe navigation operator &. calls a method only if the object is not nil:
customer = nil
customer&.upcase # => nil, instead of a NoMethodErrorThe shortcut
To predict any condition, run a two-item checklist: is the value false? Is it nil? If neither, the condition is true, however "empty" the value looks.
if cups_leftwithcups_left = 0Not false, not nil, so it passes. Probably a bug: the question is
cups_left > 0.
Drills
Answer fast — trust the rule.
Which of these values is falsy in Ruby?
What does MENU[:chai] return when the hash has no :chai key?
What is true.class?
With name = nil, what does name&.upcase return?
What does nil.to_a return?
Remember
- Only
falseandnilare falsy; everything else, including 0 and "", is truthy. - Two-item checklist: false? nil? If neither, the condition passes.
- Trap:
if countwhen you meantif count > 0; test withnil?,empty?orzero?instead.
