December 01, 2008
Older: RubyGems: Yours, Mine and Ours
Newer: Watch John Speak, Drink John Drink
Unless, The Abused Ruby Conditional
Some people hate unless
in Ruby. I personally do not, but I try to abide by a few rules. I’ll explain with some examples below. The uses that I label as “ok” below could just be personal preference, so I will not refer to them as “good”, but I would definitely avoid using the ones I label as “bad”.
Statement Modifier…Ok
I think unless
actually reads better than if !
when used as a statement modifier. For example, I think this…
raise InvalidFormat unless AllowedFormats.include?(format)
…reads better than this…
raise InvalidFormat if !AllowedFormats.include?(format)
I think the reason I like the former incarnation is because it would read like a sentence to almost anyone, even those unfamiliar with Ruby (like my mom and we all know it is important for moms to be able to read code).
Without Else…Ok
I also don’t mind using unless
when you are just checking one condition and not using else
like so…
unless foo?
# bar that thing
end
With an Else…Bad
What I dislike is when unless
is used with an else
like so…
unless foo?
# bar that thing
else
# foo that thing
end
If you have code like this, just swap the code doing the work and use if
. Trust me, it reads a lot better.
if foo?
# foo that thing
else
# bar that thing
end
The if
version just feels easier to process than the version with unless
. I think using unless
with else
is like speaking with double negatives. It slows down the next programmer in the code, as they have to think instead of just flowing through the conditional, if that makes sense.
When testing nil?…Bad
As Ryan Bates pointed out in the comments below, testing nil like this…
unless foo.nil?
# do some foo
end
…is a bit more readable like this…
if foo
# do some foo
end
unless foo.nil?
and if foo
equate to the same thing but is kind of a double negative issue, like I just mentioned about using unless
with else
. Thanks for the another bad unless
tip Ryan!
With Multiple Conditions…Bad
The reason I hate (and it is hate, not just dislike as above) unless
with multiple conditions is that I always forget whether the “not” applies to only the first conditional or to all of them. If you are wondering, the “not” does apply to all conditionals, but just talking about it has me feeling confused again, so please do not do this…
unless foo? && baz?
# bar that thing
end
Instead, I would probably do something like this…
if !foo? || !baz?
# bar that thing
end
Final Thoughts
unless
is ok but do not throw it in your code willy nilly. I said “nil” get it? Hehe. Some might say that if unless
can be so easily abused, why not avoid using it all. I guess I disagree with that, as I think it does actually improve code readability in some cases, as I mentioned above. Feel free to argue below and I will ignore you. :)
23 Comments
Dec 01, 2008
Agreed. Using “unless” can really make your head spin in certain cases.
Another case to avoid it is with “unless foo.nil?”. Just do “if foo”, it reads much better.
Dec 01, 2008
The only people that don’t like “unless” are either:
A) Old school programmers, which I can understand.
B) Blog followers, the people that let the hip blogs choose their mindset.
I’ve personally thought, from back in my C/C++ days, that “if not” sounded like the most obscure piece of dog shit I’ve ever had to read. Not that its hard to understand, but the fact that I never say “If not” in plain English.
News Flash people: Unless IS If not… and if you see it, you should think that way if you have a problem.
Now I can jive with your rules above, but people need to settle down and understand that Unless is just one of many things that makes Ruby so much of a pleasure to use for English speaking programmers.
Dec 01, 2008
@cheapRoc I’ve often felt the same way about the unless statement in Ruby – it makes various bits of code read like English making it “a pleasure to use for English speaking programmers”. The irony being that Ruby is, of course, originated from Japan!
I guess Japanese language inventors speak better English than the computer scientists who came up with all the other languages, right? ;)
Dec 01, 2008
I believe the “unless foo? && baz?” should be re-written as “if ! foo? || ! baz?”.
Either on purpose or accidentally, you’ve highlighted one of the problems with “unless” and multiple conditions. :)
Dec 01, 2008
Just want to point out that
unless foo? && baz?
should be translated toif !foo? || !baz?
(the&&
gets negated as well). De Morgan’s laws.Dec 01, 2008
Just to avoid confusion: your two last examples do different things:
“unless foo? && baz?” = “if !(foo? && baz?)” = "if !foo? || !baz?
Dec 01, 2008
I butchered that. Wanted it rendered as:
Just want to point out that
unless foo? ==&&== baz?
should be translated toif !foo? || !baz?
(the && gets negated as well). De Morgan’s laws.Dec 01, 2008
Bleh. Oh well.
Dec 01, 2008
@Rick – Haha. It was accidentally, but I updated the article.
Thanks for the corrections everyone! The && has been changed to ||. I was just making sure you were all on top of your game. :)
Dec 01, 2008
@Ryan – Good tip! Added it to the article. I figured I would forget a few.
Dec 01, 2008
Greetings,
What about this gem:
I kid, I kid… ;)
Interestingly your usage is pretty much the same as what I’ve come to find reasonable.
Oh, and @ryan, I have a mild dislike of
if foo
as a way of testing nil. It’s not intention revealing; the reader has to think about whether the variable can be nil, or if it’s intended to be a boolean, or (worst) if it’s intended to be a boolean AND can be nil. Thus,unless foo.nil?
makes sense to me as a code writer, writing for future code readers.— Morgan
Dec 01, 2008
Greetings,
lol Ah well; our sensibilities are different on the
if foo
vs.unless foo.nil?
issue. I don’t see it as a double negative, as I seefoo.nil?
as a positive assertion. (Perhaps assertion isn’t the right word, but you probably take my meaning.)Of course I never liked
if(foo) { }
in C/C++ for!NULL
testing either. There are some windmills it’s not worth tilting at, though. :)— Morgan
Dec 01, 2008
@Morgan – I can see your point, but I actually like if foo in most cases.
Dec 01, 2008
While this may not relate directly, I think it reads better. Let’s say you have this:
That can be re-written as:
When you break it down, it makes sense. But at first glance, it’s odd that it actually works.
Dec 01, 2008
@Ryan – Huh. Didn’t know that was possible. I’ll have to digest that a bit before I can decide if I like it or not. I agree at first glance it is odd but still kind of interesting.
Dec 01, 2008
Heh, I’m gonna use unless all the time.
I absolutely hate seeing this:
if !something
..
else
..
end
Mainly because I don’t see so well. The use of unless makes it much more clear to me what the intention is.
Now let’s have a discussion on when and when not to use case…select. :)
Dec 02, 2008
Dec 02, 2008
Hey,
I also like using unless for one liner. like:
do_something unless condition
or
unless this
do_this
end
I hate complicated unless statements
Dec 02, 2008
The
unless
keyword is a trap. It’s almost always easier to understandif not
.is easier to read than…
Seems like some people opt for the
unless
keyword in preference ofif !
. I agree completely. Consider using the english operator alternative as above (If precedence isn’t important).Dec 02, 2008
Oh my gosh. I can’t believe I’m seeing this kind of conversation in … err wait. We are programmers that tend to pick at the tiniest thing.
Personally I follow the english readable process.
reads better than . A grammar teacher would slap you silly (with a trout no less) if you used the phrase in a sentence.So to make this short, use
where it makes sense to use it grammatically. Unless of course it doesn’t make sense grammatically to use it :P.Dec 02, 2008
This is trivia, but ‘unless’ is not equivalent to ‘if !’ The following is an error:
(Why can’t we preview our comments?)
Dec 02, 2008
@Mark – You can’t preview because it is low on the priority chain for RailsTips right now but trust me it is on the list and some rainy day I will add it. Already made a killer preview for Ordered List, so at least I have a starting point.
Dec 03, 2008
I think
if foo
…
end
is better than the double negative
unless foo.nil?
…
end
If you don’t know that anything except nil or false is true, don’t come up with a way to bypass that: learn it!
do_something unless foo.nil?
is, IMO, stupid
do_something if foo
is much better.
Sorry, comments are closed for this article to ease the burden of pruning spam.