If (! x) vs if (x = false) в рубине

Я не понимаю следующий код:

ruby-1.9.1-p378 > puts "nil is false" unless nil
nil is false
 => nil 
ruby-1.9.1-p378 > puts "nil isn't false" unless nil == false
nil isn't false
 => nil 

В большинстве языков (как минимум, C-base), если (! cond) и if (cond == false) оценивают одно и то же. Что здесь происходит, чтобы сделать это не так?

(Я хотел бы узнать, почему, я понимаю, что так оно и есть.)

Ответ 1

Ruby считает, что false и nil являются единственными двумя "фальшивыми" значениями, а все остальное "правдиво". Это по определению и не может быть изменено (по крайней мере, в МРТ). Это определение используется для всех встроенных операторов, таких как if, unless, while, until, cond ? if_truthy : if_falsey, ||, &&,...

Запись foo == bar всегда будет вызывать метод == на foo с bar в качестве аргумента. По умолчанию nil, false, true и все остальные, подобные символам, и т.д...., равны сами по себе. Это может быть изменено, однако:

def nil.==(bar)
  super || bar == false
end
puts "nil == false" if nil == false  # => "nil == false"

В Ruby 1.9 вы также можете переопределить оператор !, поэтому unless foo не обязательно совпадает с if !foo или наоборот if foo:

def true.!
  true
end

puts "True?"   if  true # => "True?"
puts "or not?" if !true # => "or not?"

Не то, чтобы кто-нибудь рекомендовал делать что-то подобное...

Ответ 2

nil не равен false путем сравнения по ==, потому что их семантический контент отличается (nil не является информацией, false - логическое значение). Однако, если вы попытаетесь оценить nil в булевом контексте, это будет считаться False, главным образом для удобства и идиоматической совместимости с другими языками.

nil == a <=> nil != a <=> false будет иметь место практически для любого значения a, кроме nil.

Итак, вы можете только сказать, что "nil is not true" и "nil is nil". Это до тех пор, пока рубин идет своим путем.

Ответ 3

В некоторых языках вы можете использовать только логические выражения в операциях if. Попытка проверить, является ли строка или число истинным или ложным, просто глупо и бессмысленно, поэтому язык не позволит вам это сделать.

В Ruby, однако, все можно рассматривать как логическое, хотя это действительно не так. Фактически, все в Ruby действительно верно, за исключением nil и false (IIRC). Это не означает, что nil фактически равно EQUAL на false, так же как это не означает, что целое число 45 фактически равно EQUAL истинному. Они разные, разные, вещи. Но если вы собираетесь рассматривать nil как логическое (например, использовать его в if или if), тогда он как бы ошибочный.