Почему Ruby имеет TrueClass и FalseClass вместо одного логического класса?
Я работал над сериализацией значений, когда узнал об этом. У Руби есть TrueClass класс, а FalseClass класс, но у него нет Boolean класса. Я хотел бы знать, почему это.
Я вижу некоторые преимущества в использовании Boolean; например, разбор строк может быть централизован на нем.
разработчики Ruby умнее меня, поэтому должно быть много веских причин, которые я просто не вижу. Но сейчас мне кажется, что у меня есть OneClass и TwoClass вместо Fixnum.
8 ответов:
цель класса состоит в том, чтобы сгруппировать подобные объекты или объекты с подобным поведением вместе.
1и2очень похожи, поэтому для них имеет смысл быть в одном классе.trueи и не похожие. На самом деле, их
похоже, что сам МАЦ ответил на этот вопрос на A список рассылки в 2004 году.
короткая версия его ответа:"сейчас он работает нормально, добавление Булева не дает никакого преимущества".
лично я не согласен с этим; вышеупомянутый "обработка строк" является одним из примеров. Другой заключается в том, что когда вы применяете различную обработку к переменной в зависимости от ее типа (т. е. парсер yml), имеющий "логический" класс удобен - он удаляет одно "если". Это тоже выглядит более корректно, но это личное мнение.
со ссылкой на МАЦ рубиновый форум (2013):
...Там нет ничего истинного и ложного обычно разделяют, таким образом, нет логического класса. Кроме того, в Ruby все ведет себя как логическое значение....
true и false могут управляться Булевым классом, который содержит несколько значений, но тогда объект класса должен иметь внутренние значения и поэтому должен быть удален при каждом использовании.
вместо этого Ruby обрабатывает true и false как длинные значения (0 и 1), каждое из которых соответствует типу класса объектов (FalseClass и TrueClass). Используя два класса вместо одного логического класса, каждый класс не требует никаких значений и поэтому может быть различен просто по идентификатору класса (0 или 1). Я считаю, что это приводит к значительным преимуществам скорости внутри Ruby engine, потому что внутренне Ruby может обрабатывать TrueClass и FalseClass как длинные значения, которые требуют нулевого перевода из их значения ID, тогда как логический объект должен быть удален, прежде чем он может быть оценен.
так как все, кроме
falseиnilзначение true в Ruby по умолчанию, вам нужно будет только добавить парсинг строки.что-то вроде этого может работать:
class Object ## Makes sure any other object that evaluates to false will work as intended, ## and returns just an actual boolean (like it would in any context that expect a boolean value). def trueish?; !!self; end end class String ## Parses certain strings as true; everything else as false. def trueish? # check if it's a literal "true" string return true if self.strip.downcase == 'true' # check if the string contains a numerical zero [:Integer, :Float, :Rational, :Complex].each do |t| begin converted_number = Kernel.send(t, self) return false if converted_number == 0 rescue ArgumentError # raises if the string could not be converted, in which case we'll continue on end end return false end endпри использовании, это даст вам:
puts false.trueish? # => false puts true.trueish? # => true puts 'false'.trueish? # => false puts 'true'.trueish? # => true puts '0'.trueish? # => false puts '1'.trueish? # => true puts '0.0'.trueish? # => false puts '1.0'.trueish? # => trueЯ считаю, что часть "большой идеи" за Ruby-это просто сделать поведение, которое вы хотите, присущее вашей программе( например, логический разбор), а не создание полностью инкапсулированного класса, который живет в своем собственном мире пространства имен (например BooleanParser).
в Ruby nil и false являются ложными, а все остальное правда. Следовательно, нет необходимости в определенном булевом классе.
Вы можете попробовать это :
if 5 puts "5 is true" end5 оценивается как true
if nil puts "nil is true" else puts "nil is false" endвыведет "nil is false"
основная причина заключается просто в том, что это гораздо быстрее и проще реализовать булевы выражения, как это происходит в настоящее время, чем с Булевым классом, который подразумевал бы преобразование.
Как сказал вам Монгус понг, когда вы пишете "если", вы просите интерпретатора оценить вещь а потом ветка. Если бы у вас был логический класс, вам пришлось бы преобразовать оценку вещь в булево до ветвление (более одного шаг.)
помните, что такое преобразование ->Boolean будет доступно как метод Ruby в классе Boolean. Этот метод может быть изменен динамически, как и любой другой метод Ruby, что позволяет разработчику полностью испортить вещи (что не так серьезно), но ясно, что это не позволит интерпретатору оптимизировать тесты, как они должны.
вы понимаете, что это заменит несколько операций с инструкциями процессора полным вызовом метода, что дорого в Ruby (помните о методе" отправить " обработки)...
Как говорили другие, вы можете "залатать" Рубин. Создайте свой собственный класс. Вот что я придумал. Методы в классе Boolean немного глупы, но они могут быть полезны программно в какой-то момент.
class Boolean def self.new(bool) bool end def self.true true end def self.false false end end class FalseClass def is_a?(other) other == Boolean || super end def self.===(other) other == Boolean || super end end class TrueClass def is_a?(other) other == Boolean || super end def self.===(other) other == Boolean || super end end
Comments