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?
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.
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).
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.
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.
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.
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 ".
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.
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.
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