I'm new to Ruby and I was surprised when I found out that all objects are true apart from nil and false. Even 0 is true.
A nice thing about that property of the language is that you can write:
if !variable
# do stuff when variable is nil
end
My colleagues, who are more seasoned Ruby developers, insist I should choose that instead of using .nil? like so:
if variable.nil?
# do stuff when variable is nil
end
However I believe that the latter is a better option for two reasons: 1. I think it's more object oriented, especially in a language like Ruby where everything is an object and message exchange. 2. It is more readable, in my subject opinion, even if it is less compact.
Am I making a "newbie" mistake here?
-
5Are you testing for nil? or a false value?user40980– user409802015年11月13日 19:20:41 +00:00Commented Nov 13, 2015 at 19:20
-
I'm testing for nil. Basically if the variable is nil, I do something (or not)Javier Holguera– Javier Holguera2015年11月13日 19:26:01 +00:00Commented Nov 13, 2015 at 19:26
-
4If you are testing for nil, why do you want the test for false to also enter that block?user40980– user409802015年11月13日 19:26:36 +00:00Commented Nov 13, 2015 at 19:26
-
Agree, I pointed that out as another reason to prefer .nil? But they insisted that "if variable do x" is more idiomatic than "if variable.nil? do x" and preferable when you know that variable is not booleanJavier Holguera– Javier Holguera2015年11月13日 19:28:16 +00:00Commented Nov 13, 2015 at 19:28
4 Answers 4
Write what you mean. Mean what you write.
Lets take a different test. .vowel?
if char == 'a'
# do stuff
end
vs
if char.vowel?
# do stuff
end
Now, its obvious that these do not do the same thing. But if you're only expecting char
to be a
or b
it will work. But it will confuse the next developer - the second block will be entered into for the conditions where char is [eiou]
also. But for a
, it will work correctly.
Yes, it is the case that nil
and false
are the only falsy values in Ruby. However, if you are testing for nil
by testing for nil || false
, this isn't what you mean.
It means that the next developer (who happens to be a crazy axe murder who knows your home address) will read the code, and wonder why false
should go in there too.
Write the code that conveys exactly what you mean.
Consider the following:
response = responses.to_a.first
This will return the first element of responses
, or nil
. Then because conditional statements treat nil
as false
we can write:
response = responses.to_a.first
if response
# do something ('happy path')
else
# do something else
end
Which is more readable than:
if response.nil?
# do something else
else
# do something ('happy path')
end
The if (object)
pattern is very common in Ruby code. It also leads nicely to refactoring, e.g.:
if response = responses.to_a.first
do_something_with(response)
else
# response is equal to nil
end
Remember also that a Ruby method returns nil
by default. So:
def initial_response
if @condition
@responses.to_a.first
else
nil
end
end
can be simplified to:
def initial_response
if @condition
@responses.to_a.first
end
end
So we can further refactor:
if response = initial_response
do_something_with(response)
else
# response is equal to nil
end
Now you can argue that returning nil
is not always the best idea, since it means checking for nil
everywhere. But that is another kettle of fish. Given that testing for object "presence or absence" is such a frequent requirement, the truthiness of objects is a useful aspect of Ruby, albeit surprising for newcomers to the language.
Not only is if variable.nil?
read more like natural language, it also guards against a programmer accidentally assigning it a false
value and falling into your if
statement, since Ruby is a loosely typed language.
-
1So the initial comment in the original question was wrong? Should have been "do stuff when variable is nil or false"? And since code not matching comment is a bug, there's a bug straight away?gnasher729– gnasher7292015年11月15日 17:46:34 +00:00Commented Nov 15, 2015 at 17:46
-
1Correct. A simple truthiness test could introduce logic errors.Greg Burghardt– Greg Burghardt2015年11月15日 18:09:42 +00:00Commented Nov 15, 2015 at 18:09
Idiomatically, unless variable
is preferable to if !variable
. Negated if
statements are often considered a code smell as it's easier to miss the negation when skimming.
The bigger picture here is that doing nil
checks like this is also a bit of a code smell. For proper OO, aim to use the null object pattern so that this sort of check is never needed.
Tell objects what to do, don't ask them what they are. This is sometimes known as tell don't ask