Não é taquigrafia.
O +=
símbolo apareceu na linguagem C na década de 1970 e - com a idéia C de "assembler inteligente" corresponde a um modo de instrução e endereço da máquina claramente diferente:
Coisas como " i=i+1
", "i+=1
"e" ++i
", embora em um nível abstrato produzam o mesmo efeito, correspondem em baixo nível a uma maneira diferente de trabalhar do processador.
Em particular, essas três expressões, assumindo que a i
variável reside no endereço de memória armazenado em um registro da CPU (vamos chamá-la D
- pense nela como um "ponteiro para int") e a ALU do processador pega um parâmetro e retorna um resultado em um "acumulador" (vamos chamá-lo de A - pense nisso como um int).
Com essas restrições (muito comuns em todos os microprocessadores daquele período), a tradução provavelmente 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
A primeira maneira de fazer isso é desagradável, mas é mais geral ao operar com variáveis em vez de constante ( ADD A, B
ou ADD A, (D+x)
) ou ao traduzir expressões mais complexas (todas elas se resumem na operação push de baixa prioridade em uma pilha, chame de alta prioridade, pop). e repita até que todos os argumentos tenham sido eliminados).
A segunda é mais típica da "máquina de estados": não estamos mais "avaliando uma expressão", mas "operando um valor": ainda usamos a ALU, mas evitamos mover valores, pois o resultado pode substituir o parâmetro. Esse tipo de instrução não pode ser usado onde expressões mais complicadas são necessárias: i = 3*i + i-2
não pode ser operado no local, pois i
é necessário mais vezes.
O terceiro - mesmo mais simples - nem considera a idéia de "adição", mas usa um circuito mais "primitivo" (no sentido computacional) para um contador. A instrução é reduzida, carrega mais rápido e é executada imediatamente, pois a rede combinatória necessária para atualizar um registro para torná-lo um contador é menor e, portanto, mais rápida que a de um somador completo.
Com os compiladores contemporâneos (consulte C, a essa altura), habilitando a otimização do compilador, a correspondência pode ser trocada com base na conveniência, mas ainda há uma diferença conceitual na semântica.
x += 5
significa
- Encontre o local identificado por x
- Adicione 5 a ele
Mas x = x + 5
significa:
- Avalie x + 5
- Encontre o local identificado por x
- Copie x em um acumulador
- Adicione 5 ao acumulador
- Armazene o resultado em x
- Encontre o local identificado por x
- Copie o acumulador para ele
Obviamente, a otimização pode
- se "encontrar x" não tiver efeitos colaterais, os dois "encontrar" poderão ser feitos uma vez (e x se tornar um endereço armazenado em um registro de ponteiro)
- as duas cópias podem ser elididas se o ADD for aplicado
&x
no acumulador
fazendo com que o código otimizado coincida com o código x += 5
.
Mas isso pode ser feito apenas se "encontrar x" não tiver efeitos colaterais, caso contrário
*(x()) = *(x()) + 5;
e
*(x()) += 5;
são semanticamente diferentes, pois os x()
efeitos colaterais (admitir x()
é uma função que faz coisas estranhas e retorna um int*
) serão produzidos duas ou uma vez.
A equivalência entre x = x + y
e x += y
é, portanto, devida ao caso particular em que +=
e =
é aplicada a um valor l direto.
Para migrar para o Python, ele herdou a sintaxe de C, mas como não há tradução / otimização ANTES da execução em linguagens interpretadas, as coisas não são necessariamente tão intimamente relacionadas (já que há uma etapa a menos de análise). No entanto, um intérprete pode se referir a diferentes rotinas de execução para os três tipos de expressão, aproveitando diferentes códigos de máquina, dependendo de como a expressão é formada e do contexto da avaliação.
Para quem gosta de mais detalhes ...
Toda CPU possui uma ALU (unidade aritmética-lógica) que é, em sua essência, uma rede combinatória cujas entradas e saídas são "conectadas" aos registradores e / ou memória, dependendo do código de operação da instrução.
As operações binárias são tipicamente implementadas como "modificador de um registrador acumulador com uma entrada obtida" em algum lugar ", em que algum lugar pode estar - dentro do próprio fluxo de instruções (típico para o manifesto de manifestação: ADD A 5) - dentro de outro registro (típico para computação de expressão com temporários: por exemplo, ADD AB) - dentro da memória, em um endereço fornecido por um registro (típico de busca de dados, por exemplo: ADD A (H)) - H, nesse caso, funciona como um ponteiro de cancelamento de referência.
Com esse pseudocódigo, x += 5
é
ADD (X) 5
enquanto x = x+5
é
MOVE A (X)
ADD A 5
MOVE (X) A
Ou seja, x + 5 fornece um temporário que é atribuído posteriormente. x += 5
opera diretamente em x.
A implementação real depende do conjunto real de instruções do processador: se não houver ADD (.) c
código de operação, o primeiro código se tornará o segundo: de jeito nenhum.
Se houver tal código de operação e a otimização estiver ativada, a segunda expressão, após eliminar os movimentos reversos e ajustar o código de registro, será a primeira.
x += 5
que o CLRx = x + 5
? Ou é realmente apenas açúcar sintático, como você sugere?