Can anybody tell me why a lot of Ruby boolean methods use this double negation convention?
!!(boolean expression)
The double negation ensures that no matter the initial value, you will always get true
or false
, never some mystery value.
This is handy because it avoids dangling references to objects you no longer require, or having to differentiate between two types of false value, nil
and false
.
Often you will see methods written like this:
def logged_in?
!!@session_user
end
This will return true
or false
and that value can be used for whatever purpose is required. Compare that with this:
def logged_in?
@session_user
end
In this case if you save the value, you're actually saving the whole @session_user
object, which could be a fairly significant chunk of memory. This memory cannot be released until your reference to it falls out of scope. Since there is only one true
and one false
, there's no need for garbage collection.
Suppose you want to define a method that returns a boolean. For example, whether a string matches a regex.
class String
def include? regex; self =~ regex end
end
If you do the above, it will return nil
when it does not match, and an integer when it matches. In many cases, that does not matter so much (nil
is similar to false
and true
can be substituted for an integer). But if you really wanted a boolean as a return value, if you do
class String
def include? regex; !!(self =~ regex) end
end
it will return true
when it matches, false
when it does not.
In my opinion, Ruby is just a little too clever about Booleans. This is a workaround for the cases when the cleverness causes problems.
Here's the excessive cleverness: there's no Boolean class. Instead, there's a convention under which any value can serve as a boolean. In a context where a true-or-false value is required, nil
or false
means "false" and anything else means "true". The values true
and false
are not part of a special class, they're the sole members of their respective classes — they exist only to make code a little more readable.
I guess this works fine most of the time, but every once in a very long while you need a boolean value that is always true
or false
. For example, I recently needed to compare two boolean values and do something special if they were different; the only problem being, one of them was either true
or false
, while the other was either 1 or nil
. Fix? Utilize the fact that !!nil == false
and !!1 == true
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With