tags:

views:

157

answers:

3

I don't understand the following code:

ruby-1.9.1-p378 > puts "nil is false" unless nil
nil is false
 => nil 
ruby-1.9.1-p378 > puts "nil isn't false" unless nil == false
nil isn't false
 => nil 

In most languages (of a C-base, at least), if(!cond) and if(cond==false) evaluate the same. What's going on here to make that not the case?

(I'd like the details of why, I understand that that is how it is.)

+2  A: 

nil is not equal to false by comparison over == because their semantic content is different (nil is no information, false is a boolean value). However, f you try to evaluate nil in a boolean context, it will be considered False, mostly for convenience' sake and idiomatic compatibility with other languages.

nil == a <=> nil != a <=> false is going to be the case for virtually any value of a except for nil.

So you can only tell that 'nil is not true' and 'nil is nil'. This is as far as ruby goes in its ways.

Romain
A: 

In some languages, you can only use booleans in "if" statements. Trying to check whether a string or a number is true or false is just silly and meaningless so the language won't let you do it.

In Ruby, however, everything can be thought of as a boolean, even though it's really not. In fact, everything in Ruby is effectively true, except nil and false (IIRC). That doesn't mean that nil is actually EQUAL to false, just as it doesn't mean that the integer 45 is actually EQUAL to true. They're different, separate, things. But if you're going to treat nil like a boolean (i.e. use it in an if or unless) then it's as though it is false.

MatrixFrog
+18  A: 

Ruby considers that false and nil are the only two "falsy" values, while everything else is "truthy". This is by definition and can not be modified (at least in MRI). This definition is used for all builtin operators like if, unless, while, until, cond ? if_truthy : if_falsey, ||, &&, ...

Writing foo == bar will always call the == method on foo with bar as an argument. By default, nil, false, true and all other immediates like symbols, etc..., are only equal to themselves. This could be changed, though:

def nil.==(bar)
  super || bar == false
end
puts "nil == false" if nil == false  # => "nil == false"

In Ruby 1.9, you can also redefine the operator !, so unless foo is not necessarily the same as if !foo or the contrary of if foo:

def true.!
  true
end

puts "True?"   if  true # => "True?"
puts "or not?" if !true # => "or not?"

Not that anybody would recommend doing anything like this...

Marc-André Lafortune
nil isn't *actually false*, it's just *falsey*. Perfect explanation. +1. And yes, please don't override == or ! or whatever if you don't have a very very good reason.
MatrixFrog
+1 for a good answer. The same is true in PHP which had to invent the `===` operator (yes that's *three* '=')
LeonixSolutions
Thanks so much for the explanation.
aharon
Is the determination as to whether an object is truethy or falsey hard-coded into the ruby if/unless implementation?
aharon
Yes, it's hard-coded. I made the answer more explicit.
Marc-André Lafortune