Rappelez-vous que a += x
signifie vraiment a = a + x
. Le point clé à comprendre est que l'addition est évaluée de gauche à droite -- c'est-à-dire le a
sur a + x
est évalué avant x
.
Alors trouvons ce que b = (a += (a += a))
fait. Nous utilisons d'abord la règle a += x
signifie a = a + x
puis nous commençons à évaluer l'expression avec soin dans l'ordre correct :
-
b = (a = a + (a = a + a))
parce que a += x
signifie a = a + x
-
b = (a = 1 + (a = a + a))
parce que a
est actuellement 1
. Rappelez-vous que nous évaluons le terme de gauche a
avant le bon terme (a = a + a)
-
b = (a = 1 + (a = 1 + a))
parce que a
est toujours 1
-
b = (a = 1 + (a = 1 + 1))
parce que a
est toujours 1
-
b = (a = 1 + (a = 2))
parce que 1 + 1
es 2
-
b = (a = 1 + 2)
parce que a
est maintenant 2
-
b = (a = 3)
parce que 1 + 2
es 3
-
b = 3
parce que a
est maintenant 3
Cela nous laisse avec a = 3
y b = 3
comme indiqué ci-dessus.
Essayons avec l'autre expression, b = (a += a) + (a += a)
:
b = (a = a + a) + (a = a + a)
-
b = (a = 1 + 1) + (a = a + a)
rappelons que nous évaluons le terme de gauche avant celui de droite.
b = (a = 2) + (a = a + a)
-
b = 2 + (a = a + a)
y a
est maintenant 2. Commencez à évaluer le terme de droite
b = 2 + (a = 2 + 2)
b = 2 + (a = 4)
-
b = 2 + 4
y a
est maintenant 4
b = 6
Cela nous laisse avec a = 4
y b = 6
. Cela peut être vérifié en imprimant les deux a
y b
en Java/JavaScript (les deux ont le même comportement ici).
Il peut également être utile de considérer ces expressions comme des arbres d'analyse. Lorsque nous évaluons a + (b + c)
le LHS a
est évalué avant le RHS (b + c)
. Ceci est codé dans l'arborescence :
+
/ \
a +
/ \
b c
Notez que nous n'avons plus de parenthèses -- l'ordre des opérations est encodé dans l'arborescence. Lorsque nous évaluons les nœuds de l'arbre, nous traitons les enfants du nœud dans une séquence ordre fixe (c'est-à-dire, de gauche à droite pour les +
). Par exemple, lorsque nous traitons le nœud racine +
nous évaluons le sous-arbre de gauche a
avant le sous-arbre de droite (b + c)
indépendamment du fait que le sous-arbre de droite soit entre parenthèses ou non (puisque les parenthèses ne sont même pas présentes dans l'arbre d'analyse).
Pour cette raison, Java/JavaScript ne pas évaluent toujours les "parenthèses les plus imbriquées" en premier, contrairement aux règles que l'on vous a peut-être enseignées en arithmétique.
Voir le Spécification du langage Java :
15.7. Ordre d'évaluation
Le langage de programmation Java garantit que les opérandes des opérateurs sont évalués dans un format spécifique. commande d'évaluation à savoir, de gauche à droite.
...
15.7.1. Évaluer l'opérateur de gauche en premier
L'opérande de gauche d'un opérateur binaire semble être entièrement évalué avant que toute partie de l'opérande de droite ne le soit.
Si l'opérateur est un opérateur d'affectation composé (§15.26.2), l'évaluation de l'opérande de gauche comprend à la fois la mémorisation de la variable que l'opérande de gauche désigne et l'extraction et la sauvegarde de la valeur de cette variable pour l'utiliser dans l'opération binaire implicite.
D'autres exemples similaires à votre question peuvent être trouvés dans la partie liée du JLS, comme par exemple :
Exemple 15.7.1-1. L'opérateur de gauche est évalué en premier
Dans le programme suivant, l'opérateur * a un opérande de gauche qui qui contient une affectation à une variable et un opérande de droite qui contient une référence à la même variable. La valeur produite par l'opérateur reflétera le fait que l'affectation a eu lieu en premier.
class Test1 {
public static void main(String[] args) {
int i = 2;
int j = (i=3) * i;
System.out.println(j);
}
}
Ce programme produit la sortie :
9
Il n'est pas permis que l'évaluation de l'opérateur * produise 6 au lieu de 9.
19 votes
Maintenant que la poussière est retombée, ne faites jamais cela en production !
13 votes
Est-ce que c'est Java ou JavaScript ?
0 votes
@muru Soit, le comportement est le même.
5 votes
Mais s'il vous plaît, n'écrivez pas de code comme dans un environnement de production, cela peut être amusant à regarder, mais ce serait une douleur de déboguer
4 votes
@pkpnd Est-ce nécessairement le cas ? Les règles pour Java, JavaScript, ou même C++ ne sont pas garanties d'être les mêmes, même si on pourrait s'y attendre.
0 votes
@cpburnz Juste pour info, j'ai annulé votre modification parce que 2/3 des réponses abordent le problème du côté JavaScript.
2 votes
Afin de mettre les choses au clair, mon intention était de faire en sorte que les programmeurs de Java/Javascript lisent cette question, car il n'y a pas beaucoup de différences entre les opérations d'affectation pour les expressions mathématiques dans ces langages.
0 votes
@muru cela s'applique aux deux : Java et JavaScript.