El operador de incremento / decremento previo / posterior ( ++
y --
) son una sintaxis de lenguaje de programación bastante estándar (al menos para lenguajes de procedimiento y orientados a objetos).
¿Por qué Ruby no los apoya? Entiendo que podrías lograr lo mismo con +=
y -=
, pero parece extrañamente arbitrario excluir algo así, especialmente porque es tan 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 +=
solo puedo instanciar un nuevo Fixnum
y configurarlo, ¿por qué no hacer lo mismo ++
?
¿Es la coherencia en las tareas que contienen el =
carácter la única razón para esto, o me falta algo?
ruby
operators
language-design
Andy_Vulhop
fuente
fuente
+=
operador. En CI intente usar++
/--
solo dentro de condicionales, prefiriendo los más literales+=
/-=
en una declaración básica. Probablemente porque aprendí Python (mucho después de C ...)Respuestas:
Así es como Matz (Yukihiro Matsumoto) lo explica en un viejo hilo :
fuente
+=
/-=
ok? ¿Y no1+=1
sería tan malo? (Falla en IRB consyntax error, unexpected ASSIGNMENT
)+=
reemplaza el objeto al que hace referencia la variable con un objeto completamente nuevo. Puede verificar esto llamandoi.object_id
antes y despuési+=1
. ¿Por qué sería eso técnicamente más difícil de hacer++
?++
método).Una razón es que, hasta ahora, cada operador de asignación (es decir, un operador que cambia una variable) tiene un contenido
=
. Si agrega++
y--
, ese ya no es el caso.Otra razón es que el comportamiento
++
y a--
menudo confunde a las personas. Caso en cuestión: el valor de retorno dei++
en su ejemplo en realidad sería 1, no 2 (el nuevo valor dei
sería 2, sin embargo).fuente
=
parece racional tener la razón de que "todas las tareas tienen algo en ellas". Puedo respetar eso como una feroz adhesión a la consistencia.a.capitalize!
no se reasignaa
, mutará la cadena a la que sea
refiere. Otras referencias a la misma cadena se verán afectadas y si lo hacea.object_id
antes y después de la llamada acapitalize
, obtendrá el mismo resultado (ninguno de los cuales sería cierto si lo hiciera en sua = a.capitalize
lugar).a.capitalize!
afectará otras referencias a la misma cadena. Esa es una gran diferencia práctica. Por ejemplo, si tienedef yell_at(name) name.capitalize!; puts "HEY, #{name}!" end
y luego lo llama así:my_name = "luis"; yell_at(my_name)
el valor demy_name
ahora será"LUIS"
, mientras que no se vería afectado si hubiera utilizadocapitalize
una tarea.No es convencional en los idiomas OO. De hecho, no existe
++
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 quiere decir es que es convencional en C y lenguajes que imitan estrechamente a C. Ruby tiene una sintaxis algo similar a C, pero no es servil al adherirse a las tradiciones de C.En cuanto a por qué no está en Ruby: Matz no lo quería. Esa es realmente la razón final.
La razón por la que no existe tal cosa en Smalltalk es porque es parte de la filosofía primordial del lenguaje que asignar una variable es fundamentalmente un tipo diferente de cosa que enviar un mensaje a un objeto: está en un nivel diferente. Este pensamiento probablemente influyó en Matz en el diseño de Ruby.
No sería imposible incluirlo en Rubí - fácilmente se podría escribir un preprocesador que transforma todo
++
en+=1
. pero evidentemente a Matz no le gustó 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 idioma funciona de esa manera.fuente
Creo que hay otra razón:
++
en Ruby no sería remotamente útil como en C y sus sucesores directos.La razón es la
for
palabra clave: si bien es esencial en C, en su mayoría es superflua en Ruby. La mayor parte de la iteración en Ruby se realiza a través de métodos Enumerables, comoeach
ymap
cuando se itera a través de alguna estructura de datos, yFixnum#times
método, cuando necesita recorrer un número exacto de veces.En realidad, por lo que he visto, la mayoría del tiempo
+=1
es utilizado por personas recién migradas a Ruby desde lenguajes de estilo C.En resumen, es realmente cuestionable si los métodos
++
y--
se utilizarían en absoluto.fuente
Creo que el razonamiento de Matz para no gustarles es que en realidad reemplaza la variable con una nueva.
ex:
¡Ahora si alguien pudiera convencerlo de que debería llamar a #succ! o lo que no, eso tendría más sentido y evitaría el problema. Puedes sugerirlo en ruby core.
fuente
Puede definir un
.+
operador de autoincremento:Más información sobre "variable de clase" está disponible en " Variable de clase para incrementar los objetos Fixnum ".
fuente
Y en palabras de David Black de su libro "El rubí bien cimentado":
fuente
¿No podría lograrse esto agregando un nuevo método a la clase Fixnum o Integer?
devuelve 2
Parece que se agregan métodos "destructivos"
!
para advertir a los posibles usuarios, por lo que agregar un nuevo método llamadonext!
prácticamente haría lo que se solicita, es decir.devuelve 2 (ya que el adormecimiento se ha incrementado)
Por supuesto, el
next!
método tendría que verificar que el objeto fuera una variable entera y no un número real, pero esto debería estar disponible.fuente
Integer#next
ya existe (más o menos), excepto que se llama en suInteger#succ
lugar (para 'sucesor'). PeroInteger#next!
(oInteger#succ!
) sería una tontería: recuerde que los métodos funcionan en objetos , no en variables , pornumb.next!
lo que serían exactamente iguales1.next!
, es decir, mutarían 1 para ser igual a 2 .++
sería marginalmente mejor ya que podría ser azúcar sintáctica para una tarea, pero personalmente prefiero la sintaxis actual donde se realizan todas las tareas=
.Integer#pred
para recuperar el predecesor.Verifique estos operadores de la familia C en el irb de Ruby y pruébelos usted mismo:
fuente
(x++)
es una declaración no válida en Ruby.