To me, a null type being compared to anything else (even another null type) is an undefined operation. Please correct me if I'm wrong there.
Under that assumption, the following makes sense to me:
nil.is_a? Comparable
=> false
nil.respond_to? :<=
=> false
nil.respond_to? :<
=> false
nil.respond_to? :>=
=> false
nil.respond_to? :>
=> false
However, nil
does respond to the "spaceship" comparison operator:
nil.respond_to? :<=>
=> true
I cannot think of a situation where comparing nil
is even meaningful, let alone practical. Why does nil
have this behaviour?
nil
in Ruby is a singleton instance of NilClass
, which inherits from Object
. Object implements <=>
, which has its behavior defined as:
Returns 0 if obj and other are the same object or obj == other, otherwise nil. 0 means self is equal to other. 1 means self is bigger than other. Nil means the two values could not be compared.
(See the documentation)
Thus, nil <=> nil
returns 0 (they are equivalent), but nil <=> anything_else
returns nil
, which means "could not be compared".
In Ruby, it is expected that all objects respond to <=>
(including nil
), but for objects for which it is a nonsensical or undefined operation, the return value is nil
, which may then be handled as the calling code best sees fit. In the case of Enumerable's operations like #sort, it raises an exception:
[1, nil].sort
# => ArgumentError: comparison of NilClass with 1 failed
But it needn't necessarily; you could implement your own sort which just moves unsortable values to the beginning of the list:
[1, nil, 2, 3, nil].sort {|a, b| (a <=> b) || -1 }
# => [nil, nil, 1, 2, 3]