In defense of “unless” (in Ruby and elsewhere)
I recently came across John Nunemaker’s take on using “unless” in Ruby and thought I’d share my two cents.
The key to making your code more readable with “unless” to is is to think semantics, not syntax. In spoken languages if there is more that one way to say something, there will be subtle differences in meaning. In English “unless” does not mean the same as “if not”, instead it indicates an exception or unlikely condition. For example, compare:
Unless it rains, we will go to the park.
to
If it’s not raining, we will go to the park.
The first sentence suggests that rain is possible, but not likely, the second that it is likely to be raining. To get the most out “unless” in your code, use it the same way.
John gives this as example of code that’s very readable with “unless”:
raise InvalidFormat unless AllowedFormats.include?(format)
Simple, elegant, and anyone reading it will understand that we expect the format to be allowed. In the unlikely case that the format falls outside of what we expect we raise an exception. Where as with “if”:
raise InvalidFormat if !AllowedFormats.include?(format)
is just a little bit ugly and says less about what is expected.
In his post, John argues against using “if” with “else” but I disagree. Again, I think in makes for more readable code when you are testing for an unexpected condition. Consider code that checks for an inactive user:
unless (@user.inactive?)
#stuff
else
redirect_to take_of_you_hoser_url
end
Reading the code, our expected course of action, doing stuff for the user, comes first, followed by the unlikely case that an inactive user is trying to do stuff. You could of course write:
if (@user.active?)
and there’s nothing wrong with that. However, I feel that using “unless” makes it clear what is expected.
In short, if you are using “unless” as a simple macro for “if !()”, then you shouldn’t be using it at all. However, “unless” is another tool which, when used with care, can make your code clearer.
Comments