ruby operators language-design

¿Por qué Ruby no admite i++ o i-(operadores de incremento/disminución)?



operators language-design (9)

El operador de incremento / decremento pre / post ( ++ y -- ) es una sintaxis del lenguaje de programación bastante estándar (para lenguajes de procedimiento y orientados a objetos, al menos).

¿Por qué Ruby no los apoya? Entiendo que podría lograr lo mismo con += y -= , pero parece extrañamente arbitrario excluir algo así, especialmente porque es muy conciso y convencional.

Ejemplo:

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

Entiendo que Fixnum es inmutable, pero si += puede simplemente instanciar un nuevo Fixnum y configurarlo, ¿por qué no hacer lo mismo con ++ ?

¿La consistencia en las asignaciones que contienen el carácter = la única razón para esto, o me falta algo?


¿No se podría lograr esto agregando un nuevo método al fixnum o la clase Integer?

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

devuelve 2

¡Los métodos "destructivos" parecen estar anexados ! para advertir a los posibles usuarios, ¡así que agregue un nuevo método llamado next! haría prácticamente lo que se solicitó, es decir.

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

devuelve 2 (ya que el entumecimiento se ha incrementado)

Por supuesto, el next! El método debería verificar que el objeto sea una variable entera y no un número real, pero debería estar disponible.


Así es como Matz (Yukihiro Matsumoto) lo explica en un viejo thread :

Hi, In message "[ruby-talk:02706] X++?" on 00/05/10, Aleksi Niemelä <[email protected]> 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.


Creo que el razonamiento de Matz por no gustarles es que realmente reemplaza la variable con una nueva.

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

¡Ahora si alguien pudiera convencerlo de que debería llamar a #succ! o qué no, eso tendría más sentido y evitaría el problema. Puedes sugerirlo en ruby ​​core.


Creo que hay otra razón: ++ en Ruby no sería remotamente útil como en C y sus sucesores directos.

El motivo es la palabra clave for : aunque es esencial en C, en su mayor parte es superfluo en Ruby. La mayor parte de la iteración en Ruby se realiza a través de métodos Enumerable, como each y el map cuando se itera a través de una estructura de datos, y Fixnum#times método Fixnum#times , cuando necesita repetir un número exacto de veces.

De hecho, por lo que he visto, la mayoría de las veces, +=1 es utilizado por personas recién migradas a Ruby de los lenguajes estilo C.

En resumen, es realmente cuestionable si los métodos ++ y -- serían utilizados en absoluto.


No es convencional en los lenguajes OO. De hecho, no hay ++ en Smalltalk, el lenguaje que acuñó el término "programación orientada a objetos" (y el lenguaje en el que Ruby está más fuertemente influenciado). Lo que quieres decir es que es convencional en C y que los lenguajes imitan a C. Ruby tiene una sintaxis parecida a C, pero no es servil al adherirse a las tradiciones C.

En cuanto a por qué no está en Ruby: Matz no lo quería. Esa es realmente la razón última.

La razón por la cual no existe tal cosa en Smalltalk es porque es parte de la filosofía primordial del lenguaje que la asignación de una variable es fundamentalmente un tipo diferente de cosa que enviar un mensaje a un objeto; está en un nivel diferente. Este pensamiento probablemente influenció a Matz en el diseño de Ruby.

No sería imposible incluirlo en Ruby: podría escribir fácilmente un preprocesador que transformara todos ++ en +=1 . pero evidentemente a Matz no le gustaba la idea de un operador que hiciera una "tarea oculta". También parece un poco extraño tener un operador con un operando entero oculto dentro de él. Ningún otro operador en el lenguaje funciona de esa manera.


Puede definir un operador de autoincremento.

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

Se encuentra disponible más información sobre "Variable de clase" en " Variable de clase para incrementar objetos Fixnum ".


Una razón es que hasta ahora cada operador de asignación (es decir, un operador que cambia una variable) tiene a = en él. Si agrega ++ y -- , ese ya no es el caso.

Otra razón es que el comportamiento de ++ y -- menudo confunde a las personas. Caso en cuestión: el valor de retorno de i++ en su ejemplo sería en realidad 1, no 2 (sin embargo, el nuevo valor de i sería 2).


Verifique estos operadores de la familia C en Ruby''s Ruby y pruébelos usted mismo:

x = 2 # x is 2 x += 2 # x is 4 x++ # x is now 8 ++x # x reverse to 4


Y en palabras de David Black de su libro "The Well-Grounded Rubyist":

Algunos objetos en Ruby se almacenan en variables como valores inmediatos. Estos incluyen números enteros, símbolos (que se parecen a esto) y los objetos especiales verdadero, falso y nulo. Cuando asigna uno de estos valores a una variable (x = 1), la variable contiene el valor en sí mismo, en lugar de una referencia a él. En términos prácticos, esto no tiene importancia (y con frecuencia quedará implícito, en lugar de explicarse repetidamente, en las discusiones sobre referencias y temas relacionados en este libro). Ruby maneja la desreferenciación de referencias de objeto automáticamente; no tiene que hacer ningún trabajo adicional para enviar un mensaje a un objeto que contenga, por ejemplo, una referencia a una cadena, a diferencia de un objeto que contiene un valor entero inmediato. Pero la regla de representación de valor inmediato tiene un par de ramificaciones interesantes, especialmente cuando se trata de enteros. Por un lado, cualquier objeto que se represente como un valor inmediato siempre es exactamente el mismo objeto, sin importar a cuántas variables se le asigne. Solo hay un objeto 100, solo un objeto es falso, y así sucesivamente. La naturaleza inmediata y única de las variables dependientes de enteros está detrás de la falta de operadores previos y posteriores al incremento de Ruby, lo que quiere decir que no se puede hacer esto en Ruby: x = 1 x ++ # No hay operador La razón es que debido para la presencia inmediata de 1 en x, x ++ sería como 1 ++, lo que significa que estaría cambiando el número 1 por el número 2, y eso no tiene sentido.