No es taquigrafía.
El +=
símbolo apareció en el lenguaje C en la década de 1970 y, con la idea C de "ensamblador inteligente", corresponde a una instrucción de máquina y un modo de dirección claramente diferentes:
Cosas como " i=i+1
", "i+=1
"y" ++i
", aunque en un nivel abstracto producen el mismo efecto, corresponden en un nivel bajo a una forma diferente de trabajar del procesador.
En particular, esas tres expresiones, suponiendo que la i
variable reside en la dirección de memoria almacenada en un registro de la CPU ( D
por ejemplo, piense en ello como un "puntero a int") y la ALU del procesador toma un parámetro y devuelve un resultado en un "acumulador" (llamémoslo A - piense en ello como int).
Con estas restricciones (muy comunes en todos los microprocesadores de ese período), la traducción probablemente será
;i = i+1;
MOV A,(D); //Move in A the content of the memory whose address is in D
ADD A, 1; //The addition of an inlined constant
MOV (D) A; //Move the result back to i (this is the '=' of the expression)
;i+=1;
ADD (D),1; //Add an inlined constant to a memory address stored value
;++i;
INC (D); //Just "tick" a memory located counter
La primera forma de hacerlo es desóptima, pero es más general cuando se opera con variables en lugar de constantes ( ADD A, B
o ADD A, (D+x)
) o cuando se traducen expresiones más complejas (todas se reducen al presionar la operación de baja prioridad en una pila, llame a la alta prioridad, pop y repita hasta que todos los argumentos hayan sido eliminados).
El segundo es más típico de la "máquina de estado": ya no estamos "evaluando una expresión", sino "operando un valor": todavía usamos la ALU, pero evitamos mover los valores como resultado permitido reemplazar el parámetro. Este tipo de instrucción no se puede usar donde se requieren expresiones más complicadas: i = 3*i + i-2
no se puede operar en su lugar, ya que i
se requiere más veces.
El tercero, incluso más simple, ni siquiera considera la idea de "suma", sino que usa un circuito más "primitivo" (en sentido computacional) para un contador. La instrucción se acorta, se carga más rápido y se ejecuta de inmediato, ya que la red combinatoria requerida para actualizar un registro para convertirlo en un contador es más pequeña y, por lo tanto, más rápida que la de un sumador completo.
Con los compiladores contemporáneos (consulte C, por ahora), que permiten la optimización del compilador, la correspondencia puede intercambiarse según la conveniencia, pero todavía hay una diferencia conceptual en la semántica.
x += 5
medio
- Encuentra el lugar identificado por x
- Añade 5
Pero x = x + 5
significa:
- Evaluar x + 5
- Encuentra el lugar identificado por x
- Copiar x en un acumulador
- Añade 5 al acumulador
- Almacenar el resultado en x
- Encuentra el lugar identificado por x
- Copia el acumulador
Por supuesto, la optimización puede
- si "encontrar x" no tiene efectos secundarios, los dos "encontrar" se pueden hacer una vez (y x se convierte en una dirección almacenada en un registro de puntero)
- las dos copias se pueden elidir si se aplica ADD
&x
al acumulador
haciendo que el código optimizado coincida con el x += 5
uno.
Pero esto solo se puede hacer si "encontrar x" no tiene efectos secundarios, de lo contrario
*(x()) = *(x()) + 5;
y
*(x()) += 5;
son semánticamente diferentes, ya que x()
los efectos secundarios (admitir x()
es una función que hace cosas raras y devolver un int*
) se producirán dos o una vez.
La equivalencia entre x = x + y
y, por x += y
lo tanto, se debe al caso particular donde +=
y =
se aplican a un valor l directo.
Para pasar a Python, heredó la sintaxis de C, pero como no hay traducción / optimización ANTES de la ejecución en lenguajes interpretados, las cosas no están necesariamente tan íntimamente relacionadas (ya que hay un paso de análisis menos). Sin embargo, un intérprete puede referirse a diferentes rutinas de ejecución para los tres tipos de expresión, aprovechando diferentes códigos de máquina dependiendo de cómo se forme la expresión y del contexto de evaluación.
Para quien le gusta más detalle ...
Cada CPU tiene una ALU (unidad aritmética-lógica) que es, en esencia, una red combinatoria cuyas entradas y salidas están "conectadas" a los registros y / o memoria dependiendo del código de operación de la instrucción.
Las operaciones binarias generalmente se implementan como "modificador de un registro de acumulador con una entrada tomada" en algún lugar ", donde en algún lugar puede estar, dentro del flujo de instrucciones en sí mismo (típico para el contenido manifiesto: ADD A 5), dentro de otro registro (típico para el cálculo de expresiones con temporales: por ejemplo, ADD AB): dentro de la memoria, en una dirección dada por un registro (típico de la obtención de datos, por ejemplo: ADD A (H)) - H, en este caso, funciona como un puntero de referencia.
Con este pseudocódigo, x += 5
es
ADD (X) 5
mientras x = x+5
es
MOVE A (X)
ADD A 5
MOVE (X) A
Es decir, x + 5 da un temporal que luego se asigna. x += 5
opera directamente en x.
La implementación real depende del conjunto de instrucciones reales del procesador: si no hay ADD (.) c
código de operación, el primer código se convierte en el segundo: de ninguna manera.
Si existe dicho código de operación, y la optimización está habilitada, la segunda expresión, después de eliminar los movimientos inversos y ajustar el código de operación de los registros, se convierte en la primera.
x += 5
quex = x + 5
? ¿O es realmente solo azúcar sintáctico como sugieres?