You Can't Handle the Truth
Quick question. What’s the output of this code in Ruby?
amount = 0
if amount
puts 'hey'
else
puts ‘nah'
end
If you answered nah
, you’re wrong. But it’s fine because this is one of the biggest gotchas for developers who are new to Ruby. Heck, even seasoned developers like myself sometimes forget this. I blame my college CS professors for putting too much C
syntax in my brain.
Ruby has a simple rule for dealing with boolean values: everything is true except false
and nil
. This also means that every expression and object in Ruby can be evaluated against true or false. For example, you can have a method find
that returns an object when it finds one or nil
otherwise.
if o = Customer.find_by(email: ‘stevej@rip.com’)
puts o.name
else
puts ‘not found it'
end
But it’s a different story when returning a numeric value because 0 evaluates to true.
false
and nil
can also be a common source of confusion because you have 2 values that can be false. Consider the default behaviour of Hash, which returns nil if the key does not exist. If you only factor in the nil
scenario, you will have a problem when a key returns a false
value - a common scenario with code that handles configuration or settings.
In the case below, this will output missing key
h = {'a' => 1, 'b' => false}
key = ‘b'
if h[key]
puts 'found a value'
else
puts 'missing key'
end
If that’s enough confusion for you, consider this: true
, false
, and nil
are just instances of a class.
irb> true.class
=> TrueClass
irb> false.class
=> FalseClass
irb> nil.class
=> NilClass
They are global variables but you can’t set any value to it which is fine. Otherwise, there will be chaos!
irb> true = 1
SyntaxError: (irb):18: Can't assign to true
true = 1
But, this is Ruby and we can always introduce chaos. Matz, the creator of Ruby, has given us this much power because he trusts that we know what we are doing.
irb> class Bad
irb> def ==(other)
irb> true
irb> end
irb> end
irb> false == Bad.new
=> false
irb> Bad.new == false
=> true
What the heck just happened? Well, ==
is just another method call - the first is for the FalseClass
instance while the second is for the Bad
instance.
If you have been using Ruby for a while and wants to become better at it, I suggest you
get a copy of Effective Ruby
by Peter Jones.