Pourquoi Ruby ne supporte - t-il pas i++ ou i - (opérateurs increment/decrement)?

l'opérateur pré/post increment / decrément ( ++ et -- ) est une syntaxe de langage de programmation assez standard (pour les langages procéduraux et orientés objet, au moins).

pourquoi Ruby ne les soutient pas? Je comprends que vous pourriez accomplir la même chose avec += et -= , mais il semble étrangement arbitraire d'exclure quelque chose comme ça, d'autant plus que c'est si concis et conventionnel.

Exemple:

i = 0    #=> 0
i += 1   #=> 1
i        #=> 1
i++      #=> expect 2, but as far as I can tell, 
         #=> irb ignores the second + and waits for a second number to add to i

je comprends Fixnum est immuable, mais si += peut juste instancier un nouveau Fixnum et réglez-le, pourquoi ne pas faire la même chose pour ++ ?

la cohérence dans les assignations contenant le caractère = est-elle la seule raison pour cela, ou est-ce que je manque quelque chose?

123
demandé sur Andy_Vulhop 2010-09-07 20:25:20

9 réponses

Voici comment Matz (Yukihiro Matsumoto) l'explique dans un vieux fil :

Hi,

In message "[ruby-talk:02706] X++?"
    on 00/05/10, Aleksi Niemelä <aleksi.niemela@cinnober.com> writes:

|I got an idea from http://www.pragprog.com:8080/rubyfaq/rubyfaq-5.html#ss5.3
|and thought to try. I didn't manage to make "auto(in|de)crement" working so
|could somebody help here? Does this contain some errors or is the idea
|wrong?

  (1) ++ and -- are NOT reserved operator in Ruby.

  (2) C's increment/decrement operators are in fact hidden assignment.
      They affect variables, not objects.  You cannot accomplish
      assignment via method.  Ruby uses +=/-= operator instead.

  (3) self cannot be a target of assignment.  In addition, altering
      the value of integer 1 might cause severe confusion throughout
      the program.

                            matz.
87
répondu Brian 2015-01-13 17:09:42

une raison est que jusqu'à présent chaque opérateur d'affectation (c.-à-d. un opérateur qui change une variable) a un = en elle. Si vous ajoutez ++ et -- , ce n'est plus le cas.

une autre raison est que le comportement de ++ et -- souvent confondre les gens. Exemple: la valeur de retour de i++ dans votre exemple serait en fait 1, et non 2 (la nouvelle valeur de i serait cependant 2).

28
répondu sepp2k 2010-09-07 16:32:30

ce n'est pas conventionnel dans les langues OO. En fait, il n'y a pas de ++ dans Smalltalk, le langage qui a inventé le terme "programmation orientée objet" (et le langage Ruby est le plus fortement influencé par). Ce que vous voulez dire, c'est que c'est conventionnel dans C et les langues imitant de près C. Ruby ont une syntaxe un peu C-like, mais ce n'est pas servile en adhérant aux traditions C.

quant à savoir pourquoi il n'est pas dans Ruby: Matz ne voulait pas. C'est vraiment la raison ultime.

la raison pour laquelle une telle chose n'existe pas dans Smalltalk est que cela fait partie de la philosophie dominante de la langue que l'assignation d'une variable est fondamentalement un genre de chose que d'envoyer un message à un objet - il est à un niveau différent. Cette pensée a probablement influencé Matz dans la conception de Ruby.

il ne serait pas impossible de l'inclure dans Ruby - vous pouvez facilement écrire un préprocesseur qui transforme tous les ++ en +=1 . mais évidemment, Il n'aimait pas l'idée d'un opérateur qui n'est "caché affectation."Il semble d'ailleurs un peu étrange d'avoir un opérateur avec une cachée opérande entier à l'intérieur d'elle. Aucun autre opérateur dans la langue fonctionne de cette manière.

23
répondu Chuck 2010-09-07 18:29:52

je pense qu'il y a une autre raison: ++ dans Ruby ne serait pas du tout utile comme dans C et ses successeurs directs.

la raison étant, le mot-clé for : alors qu'il est essentiel en C, il est surtout superflu en Ruby. La plupart de l'itération dans Ruby est fait par des méthodes énumérables, comme each et map lors de l'itération à travers une certaine structure de données, et Fixnum#times méthode, quand vous avez besoin de boucler un nombre exact de fois.

en fait, pour autant que je l'ai vu, la plupart du temps +=1 est utilisé par les gens fraîchement migré à Ruby à partir de langues de C-style.

en bref, il est vraiment discutable si les méthodes ++ et -- serait utilisé à tous.

10
répondu Mladen Jablanović 2016-01-27 19:04:37

je pense que le raisonnement de Matz pour ne pas les aimer est qu'il remplace en fait la variable par une nouvelle.

ex:

a = SomeClass.new
def a.go
  'hello'
end
# at this point, you can call a.go
# but if you did an a++
# that really means a = a + 1
# so you can no longer call a.go
# as you have lost your original

Maintenant, si quelqu'un pouvait le convaincre qu'il faut juste appeler #succ! ou ce qui ne l'est pas, cela aurait plus de sens et éviterait le problème. Vous pouvez suggérer sur ruby.

3
répondu rogerdpack 2010-09-07 16:37:35

vous pouvez définir un .+ opérateur d'auto-incrément:

class Variable
  def initialize value = nil
    @value = value
  end
  attr_accessor :value
  def method_missing *args, &blk
    @value.send(*args, &blk)
  end
  def to_s
    @value.to_s
  end

  # pre-increment ".+" when x not present
  def +(x = nil)
    x ? @value + x : @value += 1
  end
  def -(x = nil)
    x ? @value - x : @value -= 1
  end
end

i = Variable.new 5
puts i                #=> 5

# normal use of +
puts i + 4            #=> 9
puts i                #=> 5

# incrementing
puts i.+              #=> 6
puts i                #=> 6

Plus d'informations sur la Variable de classe" est disponible en " Classe de la Variable à incrémenter Fixnum objets ".

3
répondu Sony Santos 2016-01-27 19:02:12

et selon les mots de David Black de son livre "The Well-Grounded Rubyist":

Certains objets dans Ruby sont stockés dans des variables comme des valeurs immédiates. Ces inclure entiers, les symboles (qui ressemblent :ce), ainsi que les objets spéciaux vrai, faux, et nul. Lorsque vous affectez une de ces valeurs à une variable (x = 1), la variable contient la valeur elle-même, plutôt que d'y faire référence. En termes pratiques, cela n'a pas d'importance (et il sera souvent laissé comme implicite, plutôt que à maintes reprises, dans les discussions des références et des sujets connexes dans ce livre). Ruby gère le déréférencement des références d'objet automatiquement; vous n'avez pas à faire tout travail supplémentaire pour envoyer un message à un objet qui contient, par exemple, une référence à une chaîne de caractères, par opposition à un objet qui contient une valeur entière immédiate. Mais la règle de la valeur immédiate a quelques ramifications intéressantes., surtout quand il s'agit de nombres entiers. Pour une chose, un objet représenté comme une valeur immédiate est toujours exactement le même objet, n'importe comment beaucoup de variables auxquelles il est assigné. Il n'y a qu'un objet 100, un seul objet faux, et ainsi de suite. La nature immédiate et unique des variables à limite entière est derrière le manque de Ruby de opérateurs pré-et post-increment-c'est-à-dire que vous ne pouvez pas faire cela à Ruby: x = 1 x++ # Pas d'un tel opérateur Raison est que, en raison de la présence immédiate de 1 à x, x++ serait comme 1++, ce qui veut dire que vous changeriez le chiffre 1 au chiffre 2-et cela fait a aucun sens.

2
répondu Alexander Swann 2016-05-26 14:34:05

ne pourrait-on pas y arriver en ajoutant une nouvelle méthode à la classe fixnum ou Integer?

$ ruby -e 'numb=1;puts numb.next'

renvoie 2

"Destructeur" méthodes semblent être ajouté avec ! pour avertir les utilisateurs, l'ajout d'une nouvelle méthode appelée next! aurait très bien faire ce qui était demandé c'est à dire.

$ ruby -e 'numb=1; numb.next!; puts numb' 

renvoie 2 (depuis numb a été incrémenté)

bien sûr, la méthode next! devrait vérifier que l'objet était une variable entière et pas un nombre réel, mais ce devrait être disponible.

1
répondu Sjerek 2016-01-27 19:01:07

vérifiez ces opérateurs de la famille C dans Ruby's irb et de les tester pour vous-même:

x = 2    # x is 2
x += 2   # x is 4
x++      # x is now 8
++x      # x reverse to 4
-3
répondu Aung Zan Baw 2016-01-27 19:00:04