It might be a dumb question, but can someone please explain this:
if ""
true
else
false
end
=> true (OK)
!!("")
=> true (OK)
"" === true
=> false (OK)
"" == true
=> false (But why?)
Have a nice day!
CodePudding user response:
The basic concept of this question is a deep misunderstanding of Ruby operators. Here's the short of it - there's no such thing as operators in Ruby! All this !
, =
, ==
and ===
that you throw around - these are not operators.
So what's going on?
Ruby is an object oriented language (a real one, not like that fake Java and JavaScript things) and all these fancy character sequences you think of as operators are actually method calls on the object in their left:
==
method usually checks for equality - is the object on the right equal in content.===
method is not used for "strict equality" or "identity" like it is often in other languages - some Ruby objects that implement it use it for "membership" tests, like in ranges ((1..3) === 2 ==> true
) or regular expressions (/el/ === "hello" ==> true
you can think of regular expressions as the group of all strings that would match), others implement it as equals.
So - how is the if
working? Well, if
and other "forced boolean contexts" check for "falsehood". In Ruby we recognize two false values - false
and nil
, everything else will run the truth branch of an if
. This is actually the method !
that you also used in your second example. This method is implemented in BasicObject
to return true for all objects, except if the object's type is the type of false
- FalseClass
or the type for nil
- NilClass
, in which case it returns true
.
So your examples actually mean:
- Check for the truthiness of
""
. Because that value's type is neitherFalseClass
orNilClass
, it is always true. - For the value
""
, call the method!
- which will returnfalse
because the object is neither aFalseClass
or aNilClass
- then call!
on the result, which will returntrue
becausefalse
is aFalseClass
instance. - For the value
""
call the method===
with the valuetrue
, but since it is an alias for==
- call that instead (see 4). - For the value
""
call the method==
with the valuetrue
.String
's implementation of==
will never returntrue
for an argument that isn't aString
type.
CodePudding user response:
The only falsy values in Ruby are false
and nil
. Everything else is "truthy," but not necessarily equal to true
. This includes empty objects like a String, Hash, or Array.
Pragmatically, it might help to think of ==
as "comparably equivalent to" rather than "equals." For example:
1 == 1.0 #=> true
This is true even though one is an Integer and one is a Float because they are comparably equivalent in value, even if they aren't the same object or of the same type.
In the same way, ""
is truthy because it is not comparably equivalent to false
or nil
. However, it's also not the same object type as true
, nor comparably equivalent to true
. An empty String is simply "not falsy," which makes it truthy but not actually true
.
Remember, only false
and nil
are falsy. Everything else, and I mean everything, is truthy even if it isn't strictly speaking true
.
CodePudding user response:
In Ruby, the only "falsey types" are FalseClass
and NilClass
, which have the instances false
and nil
respectively. All other values are considered "truthy". This is possibly different to what you'd expect coming from other C-like values, in which we do things like this pretty freely:
int x = get_value();
if (x) { /* implied x != 0 }
So, if you had something like this in Ruby:
puts 0 if 0 # => "0"
puts 1 if "" # => "1"
puts 2 if [] # => "2"
puts 3 if false # => nil
puts 4 if true # => "4"
puts 5 if nil # => "5"
So, if ""
acts truthy, why isn't it equal to true
? If that were how we defined ==
, then this would also need to resolve to true
then, since both values are truthy:
"1" == "2"
The difference here is that ==
is asking if two things are the same, which ""
and true
are most certainly not. Further, Ruby does not automatically convert types for you (like other languages like JavaScript do), so ""
does not automatically get converted to a boolean during its comparison.