Recientemente, me topé con preguntas sobre la predicción de la salida de código que usa en gran medida operadores de post / incremento previo en enteros. Soy un programador experimentado en C, así que me sentí como en casa, pero la gente hizo declaraciones de que Java solo copiaba ciegamente eso de C (o C ++), y que esta es una característica inútil en Java.
Dicho esto, no puedo encontrar una buena razón para eso (especialmente teniendo en cuenta la diferencia entre las formas post / pre) en Java (o C #), porque no es como si manipularas matrices y las usaras como cadenas en Java . Además, fue hace mucho tiempo cuando busqué por última vez bytecode, así que no sé si hay una INC
operación, pero no veo ninguna razón por la cual esto
for(int i = 0; i < n; i += 1)
podría ser menos efectivo que
for(int i = 0; i < n; i++)
¿Hay alguna parte particular del lenguaje donde esto sea realmente útil, o es solo una característica para traer programadores de C a la ciudad?
Respuestas:
Seguramente es una característica "traer programadores de C (o C ++) a la ciudad", pero usar la palabra "solo" aquí subestima el valor de semejante similitud.
hace que el código (o al menos fragmentos de código) sea más fácil de transferir de C (o C ++) a Java o C #
i++
es menos de escribir quei += 1
, yx[i++]=0;
es mucho más idiomático quex[i]=0;i+=1;
Y sí, el código que utiliza en gran medida operadores de post / incremento previo puede ser difícil de leer y mantener, pero para cualquier código en el que estos operadores se usen incorrectamente, no esperaría un aumento drástico en la calidad del código, incluso cuando el lenguaje no proporcionaría estos operadores. Esto se debe a que si tiene desarrolladores que no se preocupan por la mantenibilidad, siempre encontrarán formas de escribir código difícil de entender.
Relacionado: ¿Hay alguna diferencia entre los operadores Java y C ++? A partir de esta respuesta, se puede deducir que cualquier comportamiento bien definido del operador en C es similar en Java, y Java solo agrega algunas definiciones para la precedencia del operador donde C tiene un comportamiento indefinido. Esto no parece una coincidencia, parece ser bastante intencional.
fuente
x[i++]=0
es idiomático en C, pero no estoy de acuerdo con que sea idiomático en C # y Java. ¿Con qué frecuencia te encuentras con esas frases, a menos que trabajes en el dominio de ingeniería / matemáticas, que, supongo, no constituye más del 1% del código Java / C # en la naturaleza?A veces uso el incremento de postfix en las declaraciones de devolución. Por ejemplo, considera esto:
No puedes hacer esto con
index += 1
. Entonces, al menos la versión de postfix puede ahorrarte de vez en cuando algunas líneas.Dicho esto, estos operadores no son necesarios y pueden confundir a las personas. Sé que Scala decidió en contra de estos operadores (solo tiene
+=
y-=
, como sugirió), y debido al enfoque más "de alto nivel", realmente no los extraño allí. Espero que Java se desarrolle (más lentamente) en la misma dirección.Sin embargo, Java tiene muchos otros operadores que no se ven muy a menudo "en la naturaleza" (¿alguna vez usó
^=
o>>>=
?), Y a nadie le importa.fuente
^=
Es razonablemente común. Puede usarlo para voltear banderas de campo de bits, intercambiar dos enteros sin una variable temporal, y en algunos algoritmos de cifrado / hash. Sin>>>=
embargo, admito que nunca he usado . (Por otra parte, nunca he usado>>>
o<<<
en ningún programa de producción ...)He construido muchos idiomas a lo largo de los años, en su mayoría con fines especiales. Lo que sucede es que tienes una gran audiencia, y todos tienen expectativas. Al considerar cada función, debe comparar el beneficio de la función con el costo de posiblemente violar las expectativas.
Uno en el que personalmente tuve que retroceder fue la división de enteros, que normalmente se trunca hacia abajo, ¿verdad? Me gusta
3 / 2 = 1.5 = 1
, ¿verdad? Bueno, en los primeros días de Fortran, alguien decidió-3 / 2 = -1.5 = -1
(no -2). En otras palabras, si el dividendo es negativo y el divisor es positivo, se debe truncar arriba . Tenga en cuenta lo que esto implica: en ese caso, el resto es negativo . Eso viola la suposición habitual de que resto = módulo. Si está haciendo gráficos, con coordenadas enteras, esto puede ocasionar todo tipo de problemas. Entonces, en el lenguaje simplemente hice que la división de enteros se truncara todo el tiempo, y lo dijera en el documento.Y así, ¿adivina qué pasó? Todas las perras se soltaron. ¡El idioma tenía un error en la división de enteros!
No sirvió de nada decir que el viejo camino estaba roto. Era más fácil cambiarlo que discutirlo.
Entonces, para responder a su pregunta, en lenguajes como C # y Java, es simplemente más fácil incluir los operadores ++ (que personalmente me gustan) que explicar por qué no.
fuente
break
s requeridos en cada cláusula a pesar de que el lenguaje no permite fallar. Mientras que D descartó la compatibilidad hacia atrás de C ++ con C, su política es que cualquier construcción de C que D conserve debería sorprender al programador de C lo menos posible.break; case ...
;-)/
rindedouble
ofloat
(usandodouble
en casos en los que cualquiera de los dos funcionaría), y tener operadores separados para la división en pisos, truncada y "hacer lo que sea", así como el módulo, el resto y "divisible por "[este último arroja un booleano]. Yo diría que cualquier resultadoint x=y/z;
tiene una probabilidad significativa de diferir de lo que se pretendía, por lo que la expresión no debería dar ningún resultado.(a+b+c)//3
debe escribirse en la mayoría de los idiomas como un lío desagradable para lidiar con la semántica de división truncada (especialmente porque, en muchos procesadores , un piso dividido por tres podría hacerse más rápido que uno truncado!)Sí, no es nada importante en sí mismo, su único beneficio es el azúcar sintáctico que hace que sea más fácil de escribir.
La razón por la que está en C en primer lugar es únicamente porque el PDP-11 que era la base de C, en los viejos tiempos, tenía una instrucción especial para aumentar en 1. En esos días, usar esta instrucción era importante para obtenga más velocidad del sistema, de ahí la función de idioma.
Sin embargo, creo que a la gente le gusta tanto el comando que se quejarían si no estuviera allí.
fuente
Esta es una sintaxis idiomática en C para muchas situaciones (como el
for
bucle que citó), por lo que, como han dicho otros, puede ayudar a aquellos que hacen la transición a Java como un nuevo lenguaje y hace que sea más fácil portar código de estilo C preexistente. Por esas razones, incluir que era una decisión natural tomar en los primeros días de Java para acelerar la adopción del nuevo lenguaje. Ahora tiene menos sentido, porque el código más compacto se produce a expensas de exigir a los programadores que aprendan la sintaxis que no es estrictamente necesaria.Quienes les gusta lo encuentran conveniente y natural. Hacerlo sin él parece incómodo. Usarlo no gana eficiencia, es cuestión de legibilidad. Si cree que sus programas son más fáciles de leer y mantener con estos operadores, úselos.
El sentido original en C era más que simplemente "sumar 1" o "restar 1". Es mucho más que azúcar sintáctica o pequeñas ganancias de rendimiento. El operador en C significa "incremento (o decremento) al siguiente elemento". Si tiene un puntero a algo más grande que un byte, y pasa a la siguiente dirección como en
*pointer++
, el incremento real podría ser de 4 u 8, o lo que sea necesario. El compilador hace el trabajo por usted, realiza un seguimiento del tamaño de los elementos de datos y omite el número correcto de bytes:En mi máquina, esto agrega 4 a kpointer, no agrega 1. Esta es una ayuda real en C, previniendo errores y guardando invocaciones espurias de sizeof (). No hay aritmética de puntero equivalente en Java, por lo que esto no es una consideración. Allí, se trata más del poder de la expresión que de cualquier otra cosa.
fuente