73 votes

Pourquoi Ruby a-t-il TrueClass et FalseClass au lieu d'une seule classe booléenne?

Je travaillais sur la sérialisation des valeurs trouvées à ce sujet. Ruby a un TrueClass classe, et un FalseClass classe, mais il n'a pas d' Boolean classe. J'aimerais savoir pourquoi est-ce.

Je vois quelques avantages à utiliser une Boolean; par exemple, le traitement de chaîne pourrait être centralisé sur elle.

Développeurs Ruby sont plus intelligents que moi, donc il doit y avoir beaucoup de bonnes raisons que je ne vois tout simplement pas. Mais pour l'instant il me semble avoir OneClass et TwoClass au lieu de Fixnum.

60voto

Jörg W Mittag Points 153275

Le but d'une classe est à grouper des objets ou des objets avec des comportements similaires ensemble. 1 et 2 sont très similaires, donc il est parfaitement logique pour eux d'être dans la même classe. true et false sont cependant pas similaires. En fait, leur point de l'ensemble , c'est qu'ils sont exactement à l' opposé les uns des autres et ont opposé du comportement. Par conséquent, ils n'appartiennent pas à la même classe.

Pouvez-vous donner un exemple de ce genre de comportement, vous pouvez implémenter dans un Boolean classe? Je ne peux pas penser à quelque chose.

Examinons le comportement qu' TrueClass et FalseClass ont: il y a exactement quatre méthodes. Pas plus. Et dans tous les cas, les deux méthodes pour faire exactement le contraire. Comment et pourquoi voudriez-vous mettre que dans une seule catégorie?

Voici comment mettre en œuvre toutes ces méthodes:

class TrueClass
  def &(other)
    other
  end

  def |(_)
    self
  end

  def ^(other)
    !other
  end

  def to_s
    'true'
  end
end

Et maintenant dans l'autre sens:

class FalseClass
  def &(_)
    self
  end

  def |(other)
    other
  end

  def ^(other)
    other
  end

  def to_s
    'false'
  end
end

Accordé, en Ruby, il y a beaucoup de "magie" qui se passe derrière les coulisses, et qui n'est pas réellement traitée par TrueClass et FalseClass mais plutôt programmés dans l'interprète. Des trucs comme if, &&, || et !. Toutefois, en Smalltalk, à partir de laquelle Ruby emprunté beaucoup de choses, y compris le concept de l' FalseClass et TrueClass, tous ces éléments sont mis en œuvre que les méthodes, et vous pouvez faire la même chose en Ruby:

class TrueClass
  def if
    yield
  end

  def ifelse(then_branch=->{}, _=nil)
    then_branch.()
  end

  def unless
  end

  def unlesselse(_=nil, else_branch=->{})
    ifelse(else_branch, _)
  end

  def and
    yield
  end

  def or
    self
  end

  def not
    false
  end
end

Et de nouveau dans l'autre sens:

class FalseClass
  def if
  end

  def ifelse(_=nil, else_branch=->{})
    else_branch.()
  end

  def unless
    yield
  end

  def unlesselse(unless_branch=->{}, _=nil)
    ifelse(_, unless_branch)
  end

  def and
    self
  end

  def or
    yield
  end

  def not
    true
  end
end

Il y A quelques années, j'ai écrit ci-dessus, juste pour le plaisir et même publié. Outre le fait que la syntaxe est différente parce que Ruby a recours à des opérateurs alors que je n'utilise que des méthodes, il se comporte exactement comme le Rubis est builtin opérateurs. En fait, j'ai effectivement pris le RubySpec conformité testsuite et porté à ma syntaxe et ça passe.

22voto

kikito Points 23229

Il semble que Matz lui-même répondu à cette question sur une liste de diffusion de message en 2004.

Version courte de sa réponse: "pour l'instant il fonctionne bien, l'ajout d'un Booléen ne donne pas d'avantage".

Personnellement, je ne suis pas d'accord avec cela; le fameux "traitement de chaîne" en est un exemple. Un autre est que lorsque vous appliquez un traitement différent à une variable en fonction de son type, (c'est à dire un yml de l'analyseur) d'avoir un "Boolean" class est très pratique - il supprime un "si". Aussi, il semble plus correct, mais c'est un avis personnel.

4voto

Asher Points 735

le vrai et le faux pourrait être géré par une classe Boolean qui a tenu plusieurs valeurs, mais alors la classe de l'objet devait avoir des valeurs internes, et donc d'être référencé avec chaque utilisation.

Au lieu de cela, Ruby traite le vrai et le faux, tant les valeurs (0 et 1), dont chacun correspond à un type de classe d'objet (FalseClass et TrueClass). À l'aide de deux classes au lieu d'une seule classe Boolean, chaque classe ne nécessite pas de valeurs et, par conséquent, peuvent être distingués tout simplement par son identificateur de classe (0 ou 1). Je crois que cela se traduit par une augmentation considérable de la vitesse avantages internes à l'Ruby moteur, parce que l'interne Ruby peut traiter TrueClass et FalseClass aussi longtemps valeurs-seuil à zéro de la traduction à partir de leur valeur d'ID, alors qu'un objet Boolean devrait être de-référencé avant qu'il puisse être évalué.

3voto

Slipp D. Thompson Points 6293

Depuis tout mais false et nil true en Ruby par défaut, vous n'aurez qu'à ajouter de l'analyse de la Chaîne.

Quelque chose comme cela pourrait fonctionner:

class Object
  ## makes sure any other object that evaluates to false will work as intended
  def trueish?; !!self; end
end

class String
  ## parses certain strings as false; everything else as true
  def trueish?
    # check if it's a literal "false" word sting
    return false if self.strip.downcase == 'false'

    # check if it's a numerical zero string
    [:Integer, :Float, :Rational, :Complex].each do |t|
      begin
        return false if Kernel.send(t, self) == 0
      rescue ArgumentError
        # raises if the string could not be converted,
        #   in which case, we'll continue on
      end
    end

    return true
  end
end

Lorsqu'il est utilisé, ce serait vous donner:

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

Je crois qu'une partie de la "grande idée" derrière Ruby est juste de rendre le comportement que vous avez le désir inhérent à votre programme (par exemple, l'analyse booléenne), plutôt de la création d'un entièrement encapsulé classe qui vit dans son propre espace de noms du monde (par exemple, BooleanParser).

1voto

Mongus Pong Points 6902

En Ruby, zéro et false sont faux et tout le reste est vrai. Il n'y a donc pas besoin d'une classe booléenne spécifique.

Tu peux l'essayer :

 if 5
  puts "5 is true"
end
 

5 est évalué à vrai

 if nil
    puts "nil is true"
else
    puts "nil is false"
end
 

Imprimera "néant est faux"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X