In Ruby, why does a equality with nil ("Date.new == nil") return nil?
I checked the source and here's what I found out:
The comparison operators defined by Comparable all use the function rb_cmpint
together with <=>
. rb_cmpint
raises an exception when one of the operands is nil.
So the operators of Comparable raise an exception if the rhs is not comparable to the lhs. I.e. 5 < 2
is false, but 5 < "la"
raises an exception. They do this to differentiate between cases where <
is not true because the rhs is smaller and cases where it's not true because the rhs is not comparable. Or in other words: When x < y
is false that implies that x >= y
is true. So in cases where that would not be the case, it throws an exception.
==
raising an exception would be bad, because ==
usually does not (and should not) require its operands to be comparable. However ==
uses the same method as the other operands, which does raise an exception. So the whole function is simply wrapped in an rb_rescue
. And that returns nil
if an exception is thrown.
Note that this only applies to ruby 1.8. This has been fixed in 1.9 and now ==
never returns nil
(except of course if you define your own ==
that does).
The Date class includes the Comparable#==
method, but that method invokes the <=>
method of the receiver. In this case that's Date#<=>
, which expects another Date object. When it receives nil
it returns nil
. This behavior certainly seems inconsistent, and I don't know the reasons behind it.