If vs. Unless in Ruby
Do you find
unless to be confusing? I know I do. Especially if it’s combined with one or more boolean operators.
Take this example.
def validation "Bingo!" unless email_invalid? || email_missing? end
Do you find that easy to read? I know I don’t.
Figuring out boolean operator precedence is hard enough, but throwing
unless in the mix is just too much for my brain to process.
To me, the following feels much easier to understand.
def validation "Bingo!" if email_present? && email_valid? end
There’s something about
if that makes it easier to read and understand.
Unless vs. if
unless is the exact opposite of
if. It’s a negated
In other words, the following three examples are equivalent.
unless number.even? # runs if `number` is NOT even else # runs if `number` is even end
if not number.even? # runs if `number` is NOT even else # runs if `number` is even end
if !number.even? # runs if `number` is NOT even else # runs if `number` is even end
You won’t see
unless...else used very often in real life code because you can always replace it with an
unless true # do falsy stuff else # do truthy stuff end
Can be written as an
if...else statement. Like so.
if true # do truthy stuff else # do falsy stuff end
How to use unless
A good use for
unless is when you want to check something at the beginning of a method. Also known as a guard clause.
def my_method(name) return unless name.empty? # ... end
I find that using the modifier version of
unless, as a guard clause improves readability.
What is the value of the if/unless modifier?
If you’re expecting a return value from the modifier, you might be surprised to find that there isn’t one. Let us test this.
What does the following method return if
name is empty?
def some_method(name) "Bingo!" unless name.empty? end some_method("") # => nil
Likewise, what does the following
if expression evaluate to when
number is 0?
def some_method(number) "Bingo!" if number > 0 end some_method(0) # => nil
As you can see, both of them are
nil. But why is that?
- It’s because the expression never runs.
- An empty code block returns
So if there is no code to run, the entire block (i.e. the method) returns
Check out these other empty code blocks.
class Foo; end # => nil begin; end # => nil eval("") # => nil