Подтвердить что ты не робот

В Ruby, почему равенство с nil ( "Date.new == nil" ) возвращает nil?

При написании некоторого rspec сегодня я столкнулся с неожиданным поведением при сравнении экземпляров Date (и Time) с nil. Здесь образец с использованием raw ruby ​​(без Rails или других библиотек):

[email protected] ~ $ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]
[email protected] ~ $ irb
>> 1 == nil
=> false
>> "string" == nil
=> false
>> :sym == nil
=> false
>> false == nil
=> false
>> [] == nil
=> false
>> {} == nil
=> false
>> Proc.new {} == nil
=> false

До сих пор, так хорошо, правильно?

>> Date.new == nil
=> nil
>> Time.new == nil
=> nil

Дата выполняет свое собственное ===, которое отлично работает:

>> Date.new === nil
=> false

Есть ли какие-либо объяснения, почему это происходит или почему это желаемое поведение? == похоже, реализовано из Comparable. ==, однако документация по этому поводу не дает никаких указаний на то, что она когда-либо вернет нуль. Какое конструктивное решение для этого?

Update! Это не относится к 1.9.2:

$ irb
ruby-1.9.2-p136 :001 > require 'date'
 => true 
ruby-1.9.2-p136 :002 > Date.new == nil
 => false 
ruby-1.9.2-p136 :003 > Time.new == nil
 => false 
4b9b3361

Ответ 1

Я проверил источник и вот что узнал:

Операторы сравнения, определенные с помощью Comparable all, используют функцию rb_cmpint вместе с <=>. rb_cmpint вызывает исключение, когда один из операндов равен нулю.

Таким образом, операторы Comparable вызывают исключение, если rhs не сопоставимо с lhs. То есть 5 < 2 - false, но 5 < "la" вызывает исключение. Они делают это, чтобы различать случаи, когда < не является истинным, потому что rhs меньше, а случаи, когда это не так, потому что rhs не сопоставим. Или, другими словами: Когда x < y является ложным, это означает, что x >= y истинно. Поэтому в случаях, когда это не так, оно генерирует исключение.

== Создание исключения будет плохим, потому что == обычно не (и не должно) требует, чтобы его операнды были сопоставимыми. Однако == использует тот же метод, что и другие операнды, что делает исключение. Таким образом, вся функция просто завернута в rb_rescue. И это возвращает nil, если генерируется исключение.

Обратите внимание, что это относится только к ruby ​​1.8. Это было исправлено в 1.9 и теперь == никогда не возвращает nil (за исключением, конечно, если вы определяете свой собственный ==, который делает).

Ответ 2

Если вы зависите от этого для кода, вы всегда можете использовать .nil? метод, на который реагирует любой объект Ruby.

>> Date.new.nil?
=> false

Ответ 3

Класс Date включает метод Comparable#==, но этот метод вызывает метод <=> получателя. В этом случае Date#<=>, который ожидает другого объекта Date. Когда он получает nil, он возвращает nil. Такое поведение, безусловно, кажется непоследовательным, и я не знаю причин этого.

Ответ 4

Это происходит потому, что вы не можете сравнивать вещи, которые не определены. Это желательно, потому что если хотя бы один из ваших операндов не определен, вы не можете сделать никакого вывода о результате, который отличается от утверждения правды.

Многие языки рассматривают nil и false то же самое, что подозревается исключительно для удобства. Это, конечно, не математически правильно.