bangbang your nil is dead
March 26, 2007 14:07 (Sydney Australia), updated 131 days later
In Ruby, methods ending in question marks should return booleans.
Update I: the above statement is misleading, if not incorrect. You shouldn’t ever need to check for equality to true or false (if logged_in? rather than if logged_in? == true), and its arguably more the Rubyish to let it “just work” rather than force it into explicitness.
@current_user = nil
def logged_in?
@current_user
end
logged_in? == true # => false
logged_in? == false # =; false
# hrmm, that's interesting... neither true nor false
@current_user = "A pretend user object"
logged_in? == true # => false
logged_in? == false # => false
# hrmm, still neither true nor false. Who am I? Where am I? I'm confused!
One way to solve this would be to redefine logged_in? to look like this:
def logged_in?
@current_user != nil # or !@current_user.nil?
end
That’s alright, but there’s much more succinct way to do the same thing: use the not operator (!) twice, or in other words; bangbang!
@current_user = nil
def logged_in?
!!@current_user
end
logged_in? == true # => false
logged_in? == false # => true
@current_user = "A pretend user object"
logged_in? == true # => true
logged_in? == false # => false
# much better! :)
...and, if you’re as sick and twisted as my colleague David Lee, you could abuse this to make a blasphemic unimplemented test method:
def test_my_code_should_do_something
!!?!
end
The moral of the story: you usually want to chuck a double bang (!!) in a boolean method. The most common exception to this humble moral is that if you’re just calling another boolean method (such as include?) from within yours you can assume it does the right thing and leave out the bangbang!
Update II: ignore this unmoral blasphemy. Use a double bang at your own discretion when you want to force some object into an explicit true/false. I’ve sometimes found it useful when I want methods ending with a question mark to return true/false.
Update III: I really feel I jumped the gun with this article and could have encouraged some cargo culting for recommending you use it in boolean methods and not explaining the double-negation itself. I also should have stated my opinion at the time more clearly: “though boolean methods work quite naturally by returning an object, nil, true or false I prefer them to always return a true or false”. I see how forcing it into a boolean is un-Rubyish though I still feel there’s an expectation that boolean methods return booleans, not to mention its a convention which Ruby core itself upholds

Comments
Lachie
I like your bangbang trick. But! I think that the counterpoint to your general argument is that we should trust the axioms of the language. Its where the power comes from.
In Java, nothing is a boolean but a boolean. I kind’ve feel that’s the logical conclusion of the argument here.
The most basic kind of Ruby’s duck typing is that only false and nil are considered to be false.
I reckon that explicitly testing logged_in? false or logged_in? true obviates the advantages of duck typing.
Tim Lucas
You’re probably right Lachie, I just thought as Ruby seems to be explicit, and it was rarely the case where a predicate method returned anythin but a
trueorfalsevalue it was best to standardize. To return anything else seemed illogical.I’ve scoured ruby-talk and found two threads: booleans and Zero is true. I guess Dave Thomas hits the nail on the head: why have true/false at all? I figured if they existed it made sense to use them as the result of predicate methods, but it looks that it wasn’t always the case.
Lachie
That’s a good point about having true and false at all. I guess it allows for nuances.
My perspective is a bit historical: in perl 0, undef and ”” are all false. The Ruby way seems so much nicer than perl, that I find it hard to fault :)
Just remembered this: http://rhg.rubyforge.org/chapter02.html
Underneath, false, true and nil aren’t objects at all. They’re just #defined integers.
Qfalse is actually 0, so that it can be considered false in C as well. (Qtrue is 2 and Qnil is 4)
Evgeny
This is wrong. Please see my comment on http://www.johnwulff.com/articles/2007/04/11/double-not
in short:x = false !x.nil? == !!x => falseTim Lucas
@Evgeny: The only thing that’s wrong is claiming
!!x == !x.nil?, which was John’s typo, not mine :)...which is exactly what you’d expect, I’d expect.
Evgeny
But what if my variable/method is a boolean? And it has 3 states, true/false/nil … then the !! will transform the nil into a false, which is not what .nil? does.
For example – if I want to save a gender of a person in the database as a boolean. I could have a method like so:
But if I use:
That would not be the same method, so in this case !! is not .nil?. Or am I missing something?
Tim Lucas
Evgeny: Sorry if my article is confusing… I’m not claiming
!! == .nil?. Double negation is most useful when you know something is going to be some object or nil (like in my example from production code) or where you want both a NilClass or FalseClass to return false, and anything else to return true (just like how the attribute boolean methods work in ActiveRecord).re. your
gender_to_textmethod: why are you storing a boolean in the first place? To save row space? Regardless of your reason, how you store that attribute in the database shouldn’t matter to anything but the Person class (and especially not to a helper method such asgender_to_text)Then you can go
@person.gender.to_s, which is a more Ruby way of sayinggender_to_text(@person.gender).To comment on this article you must have javascript enabled.