Among the things that people new (and old!) to Ruby find delightful are the little things it does to make the language feel intuitive. Case in point: unless
.
The unless
keyword is just if
in reverse. It’s a conditional statement that executes only if the condition is false, instead of true. This lets you write little gems like this:
i += 1 unless i > 10
unless person.present?
puts "There's no such person"
end
However, as with anything that gives you a little power, it can be abused. The following abomination is but a sample:
unless !person.present? && !company.present?
puts "do you even know what you're doing?"
else
puts "and now we're really confused"
end
I do not doubt that there are people out there who can decipher the logic above without breaking a sweat. But for most folks, combining negations, multiple conditions, and (gasp!) else clauses with an “unless” statement makes for challenging reading. It also makes it far too easy to introduce bugs into the logic.
Some rules of thumb when using unless
:
- Avoid using more than a single logical condition.
unless foo?
is fine.unless foo? && bar?
is harder to parse. - Avoid negation. “Unless” is already negative. Piling more on only makes it worse.
- Never, ever, ever use an
else
clause with anunless
statement.
Not only will others thank you when they have to read your code, you’ll thank yourself when you have to return to that code a month or two down the road.
GregT
on 10 Dec 10Maybe I am missing the point, but is ‘IF !’ or ‘IF NOT’ really so hard to read that it deserves another keyword? This seems like the very definition of ‘syntactic sugar’. I am not sure if meaningless variation between programming languages is really a good thing. MeaningFUL, sure, but things like this? Anyways Happy Holidays to all.
Joel Finkle
on 10 Dec 10I’ve always been fond of the similar clauses in Perl and VAX Basic.
I do see a (rare) case where unless…else is valid, though: Presenting the important alternative first is good coding for documentation: you want to understand the primary objective. Having an “else” lets you display user input error message, handle an exceptional condition, etc.
I do agree that “if” with a negation probably works better, but there may be a few times when unless…else is sensible.
Note: Microsoft took some heat for proposing an “Isnt” operator some time ago, to prevent ugly code like If Not obj Is Nothing then instead If obj Isnt Nothing then
Negation is important.
DHH
on 10 Dec 10Greg, it’s not about hard or not hard. It’s about pleasure and flow. Ruby has so much grace as a programming language because it goes beyond merely making something possible and turns it into something beautiful.
Jamis
on 10 Dec 10To go along with David’s comment, the point with “unless” is also that it can expose intention better, when used right. Yes, “if !present” and “unless present” are logically identical, but semantically the “unless” version emphasizes the negation.
JBoss
on 10 Dec 10DarylM
on 10 Dec 10Grace is clearly in the eye of the beholder.
unless present
is a negative statement. I more agree with GregT, it is useless syntactic sugar and is, in a differing opinion, less elegant or readable than
if not present
I also dislike reading statements of fact and then later finding out there is a condition on that fact (trailing unless)
- “Thats just my opinion, I could be wrong.” Dennis Miller
- “I May Be Wrong but I Doubt It.” Charles Barkley
David Andersen
on 10 Dec 10I think
DO THIS unless THIS CONDITION IS MET
is more intuitive and readable than
if THIS CONDITION IS MET then DO THIS
because the action is first, the thing that is probably going to happen. This is especially true if the conditional logic becomes complicated.
I think Strunke and White would agree.
JBoss
on 10 Dec 10DaryIM, while grace is subjective, in my example above, “riding my bike” is the intent, which is more likely to be executed than not (exceptionally when it’s snowing). That feels right to me.
Scott
on 10 Dec 10I agree with some others here that “unless person.present?” seems unnecessarily abstracted from the phrase “There’s no such person”. Ask yourself which requires less mental jumps to note the equality of these statements.
Set A: unless person.present? "There's no such person present."
Set B: if !person.present? “There’s no such person present.”
Am I wrong in feeling that Set B flows better?
David Andersen
on 10 Dec 10Set C: “There’s no such person present.” unless person.present?
Scott
on 10 Dec 10When my mind summarizes the unless code, it sounds like this:
“Unless the person is present, say ‘The person is not present’.
When my mind summarizes the if code, it sounds like this:
“If the person is not present, say ‘The person is not present’.
Bryan
on 10 Dec 10Coming from C# and now programming more with Ruby, I really appreciate the “conversational” nature of Ruby. This is but one example of many.
Joe
on 10 Dec 10These comments need an upvote mechanism and/or sub-comments. That way we can all get a better feel for how many others agrees with who.
UP GregT UP JBoss for a good point—it’s more readable, but it’s also very easy to scan past and get the wrong interpretation.
‘unless’ is just another thing to remember while scanning code. Think of QBasic’s While and Until blocks. If there was a demand for coding negation without using ’!’ or ‘not’, these constructs would still be around.
Dmitriy
on 10 Dec 10FWIW:
(not A) and (not B) = not ( A or B )
(not A) or (not B) = not ( A and B )
http://en.wikipedia.org/wiki/De_Morgan’s_laws
Jim
on 10 Dec 10I use it simply because I can, and I like it. How much more fun is that?
David Lewis
on 10 Dec 10First, the Ruby way for the first one is:
puts "There's no such person" unless person.present?which is even more graceful!
Second, while “unless” is indeed nice, it’s such a small thing in the context of so many wondrous, graceful and elegant facets of ruby, small, medium and large. It’s hardly worth mentioning. Of course, there are a number of not-so-graceful aspects of Ruby too, like the arbitrary meanings of various variants, but they too are small in the face of global elegance.
Mark Wilden
on 10 Dec 10I just used this construct for the first time:
return if shows.empty? unless display_even_if_empty?SteveP
on 11 Dec 10“if !” is less visually distinguishable so I avoid it unless it is absolutely necessary. Which is a clearer expression of my intent than saying ‘if absolutely necessary I use “if !” because it is less visually distinguishable.
sound of one hand clapping
on 11 Dec 10Unless you are attending, tell me you are not attending.
huh? what? This is linguistically equivalent to: unless person.present? puts “There’s no such person” Who talks that way? That’s right: no one. These phrases are easier to understand.
If you will not be present, tell me.
or
Tell me if you will not be attending.
Berserk
on 11 Dec 10My rule of thumb (since “unless” is in Perl too) is to not use it unless it makes perfect sense.
Why is
i += 1 unless i > 10
better than either of
i += 1 if i < 11
i += 1 if i <= 10
?
nwmcsween
on 11 Dec 10My take on this is simple. For the unimaginative: let’s go fishing, unless you work vs. if you don’t work lets go fishing. One puts the subject before the predicate which may help with readability, unless you can’t understand unless :).
T
on 11 Dec 10I don’t think grace and “syntactic cuteness” (that’s what the unless keywords seems to be to me) should ever outweigh simplicity and ease of use. Introducing such a keyword means people have to be able to read it and think about where they want to use it. This cognitive burden doesn’t justify the few cases where unless might come in handy.
I’m however not familiar with the Ruby philosophies in general, maybe this is exactly what you guys want :)
Tadas
on 11 Dec 10guys, don’t forget the “blank?” ! (Rails only, not Ruby)
puts “I’m rich” unless money_in_the_pocket.blank? is the same as puts “I’m rich” if money_in_the_pocket.present?
but I totally agree with Jamis that these are the language gems and allow to express intention and emphasis depending on what you want exactly.
Ape-Inago
on 12 Dec 10I like similar notations in perl:
do (something) until (condition met)
vs
while (condition met) do (something)
The issue is that a lot of coders are so used to thinking in the if-then way that the intuitiveness of unless is no longer intuitive.
David O.
on 12 Dec 10That’s good rule of thumb, Jamis. Perhaps the abuse is a result of some people wanting to use what they consider a novel syntax in as much statements as possible.
wilman
on 12 Dec 10Guys,
IMHO I think what Jamis tried to point out in this article is what, according to his experience, is a better usage of “unless”. And he made his point correctly, I guess.
The rest of the comments “judging” if “unless” should or shouldn’t exist, according to what everyone prefers to use as a programming language, is up to them.
I mean, we’re all programmers I guess (otherwise we wouldn’t be commenting this post) and we all have experience in using different languages.
So, as in the OSs battle, everyone is free to use whatever they feel more comfortable with. So I guess we could agree or disagree with what Jamis is stating but leaving the programming language aside from the conversation, don’t you think?
With all due respect to all opinions.
RvdH
on 12 Dec 10present? also has an opposite, which is called blank?
So instead of writing “unless person.present?”, I would write “if person.blank?” So, when blank? or present? can be used, I only use “if”, never unless. Of course using if !person.present? should also be if person.blank?
Also, I agree with Berserk that i += 1 if i < 11 is better.
manuel
on 13 Dec 10I think unless is borrowed from Lisp… And is fantastic…
Jaime
on 15 Dec 10@sound of one hand clapping “Unless you are attending, tell me you are not attending.” What the hell? I’m pretty sure you made that interpretation just to disagree with the sentiment that unless is actually useful. The equivalent IF version to that would be “If you are not attending, tell me you’re not attending”, which sounds equally bad.
- UNLESS Jim is present, say “Jim is not present” - IF Jim is NOT present, say “Jim is not present”
It’s a matter of taste which one of the above you might prefer, but the reality is that they’re pretty much equal in readability. Unless does have the benefit of carrying more weight in comparison to If ! when you have a screen full of if statements. The real problems with Unless are that some people love to abuse it, and that lots of programmers coming from X or Y language just aren’t used to the syntax and have been using if ! for years. I understand people have their preferences and opinions, and I certainly don’t want to convince people to switch from if to unless statements, but the reality is that it can easily make more sense than If statements if used in the cases where they should be used.
Chris Whamond
on 15 Dec 10Nice post, Jamis. I find “unless” is very helpful when rendering partials in views:
<% unless user_signed_in? %>
<%= render ‘some_pitch_to_join_the_site’ %>
<% end %>
or…
<% unless session[:omniauth] %>
“Be Part of the Community!”
<% end %>
And it’s good in controllers, too:
ssl_required :new, :create unless Rails.env.development?
I love little “Ruby tidbit” posts like this. Keep ‘em coming, Jamis!
This discussion is closed.