Odd Ruby If Statement Question
I've noticed this little oddity(I think) in If Statements in Ruby. Here's an example:
my_number = nil
if my_number < 3
'number is less than 3'
end
Obviously, when you run this code you'll get a "comparison of Fixnum with nil failed" error. Now here's something strange. If I make开发者_如何学C a little change in the If Statement to check for nil, it works fine. Example:
my_number = nil
if my_number && my_number < 3
'number is less than 3'
end
Adding the check for nil makes it not crash. This may all sound stupid but I can't figure out why that works. Shouldn't it still throw an error?
Thanks to anyone who can explain this. :) Thanks!
Boolean expressions are evaluated in what is known as "short circuit" fashion. That is, as soon as it know the result, it doesn't keep trying to evaluate expressions.
So it does the if my_number
and since that's false
, there is no need to continue, because false && <anything>
is always false.
This is a useful language feature, and many languages work like this (the original Visual Basic is one exception that I can think of) because it lets you do exactly this sort of test without requiring cumbersome nested 'if's.
This is no way specific to Ruby: I've noticed this behaviour in all languages I've ever used, from Pascal to Java.
If you have boolean expression b1 && b2 && b3 ... && bn
, most languages guarantee that bi
will be evaluated from left to right and if some bi
turns out to be false
, evaluation will be stopped. (because whole expression is false then). Same for boolean ||
operator.
It has to be OK to test for nil, so if nil
or something like it is OK in almost every language.
But for an arithmetic comparison, if it didn't throw an exception it would have to return true or false. Either way is problematic.
True kind of doesn't make sense, as nil would be both < and > than 3.
False is almost as bad, as now nil < 3
and nil >= 3
are both false, and that's not ideal.
So, the comparison method throws an exception. Problem solved.
nil is "falsy". Try this in irb:
irb(main):001:0> puts "Nil is true " if nil
=> nil
irb(main):002:0> puts "Nil is not true " if !nil
Nil is not true
=> nil
nil isn't the same as false, but making it act as such help a lot in loops and other tests:
false == nil
=> false
Since the first part of your and is false ruby does the lazy thing and doesn't even bother to evaluate the next bit, if it's > 3.
What's happening is called short-circuit evaluation. You're statement can be thought of like this:
if( my_number )
if( my_number < 3)
'number is less than 3'
end
end
Since the first condition is false there's no reason to evaluate the second condition of the statement -- the my_number < 3 part.
精彩评论