7 janvier 2015

Chaîne des affectations et chronologie d'exécution en JavaScript

Avec des expressions JavaScript comme :

a = b = 4;
c[i] = c[++i] = 4;

les opérateurs d'affectation sont évalués de droite à gauche, mais chaque opérande est d'abord évalué distinctement de gauche à droite.

Ainsi, dans la chronologie de l'exécution, les opérandes sont individuellement évalués à partir de celui de gauche, avant d'être chaînés à partir de la droite via l'opérateur d'affectation. L'expression est alors globalement évaluée à rebours des évaluations individuelles.

La chaîne des opérateurs d’affectation


Cette inversion viendra compléter (*) la notion d'associativité de l'affectation exposée par
David Flanagan
dans la cinquième édition de JavaScript, la référence, traduction d'
Hervé Soulard
 :

"L’associativité de l’opérateur d’affectation est de droite à gauche, ce qui signifie que, lorsque plusieurs opérateurs d’affectation apparaissent dans une expression, ils sont évalués de droite à gauche. Ainsi, vous pouvez écrire le code suivant pour affecter une seule valeur à plusieurs variables :

i = j = k = 0;

Souvenez-vous que chaque expression d’affectation a une valeur qui est la valeur du côté droit. Ainsi, dans le code ci-dessus, la valeur de la première affectation (à l’extrême droite) devient la valeur de droite pour la seconde affectation (la valeur du milieu) et cette valeur devient la valeur de droite (la plus à gauche) de la dernière affectation."

page 77 : I Noyau JavaScript ; 5. Expressions et opérateurs ; Opérateurs d'affectation

Chronologie des exécutions opérande par opérande

Pour constater que l'évaluation de chaque expression d'opérande se fait dans le sens inverse de la chaîne des affectations (L’associativité de l’opérateur d’affectation est de droite à gauche), lisons le résultat du test suivant :

var alpha = new Array(3),
    beta = new Array(3),
    gamma = new Array(3),
    index = -1;
alpha[++index] = beta[++index] = gamma[++index] = index;
console.log("alpha :",alpha,"beta :",beta,"gamma :",gamma);
=>
"alpha" : [2, undefined, undefined]
"beta" : [undefined, 2, undefined]
"gamma" : [undefined, undefined, 2]

C'est le premier élément du tableau 'alpha' qui est affecté. Ainsi, l'incrémentation initiale de la variable 'index' n'est pas due à l'expression 'gamma[++index]', mais à l'expression 'alpha[++index]', en allant de gauche à droite.
Ça manifeste que les opérandes sont évalués distinctement de gauche à droite, avant l'action de droite à gauche des opérateurs d'affectation.

Note sur les notions d'associativité

Sans confusion avec la notion d'associativité en algèbre, dans laquelle ces deux formules-ci sont équivalentes :

opérande opérateur (opérande opérateur opérande)
(opérande opérateur opérande) opérateur opérande

Mais entendre ici "associativité" comme le chaînage déterminé - de droite à gauche - de la suite des affectations, dit en l'occurrence et autrement :

alpha[++index] = (beta[++index] = (gamma[++index] = index));

Cf. page 65 (id.) : L’associativité d’un opérateur spécifie l’ordre selon lequel les opérations ayant la même priorité sont effectuées.

(*) 4.7.7 Order of Evaluation


Venant de constater que la sixième édition de l'ouvrage de
Flanagan
, JavaScript - The Definitive Guide, non (encore ?) traduit, comprend le sujet de mon billet :

"Operator precedence and associativity specify the order in which operations are performed in a complex expression, but they do not specify the order in which the subexpressions are evaluated. JavaScript always evaluates expressions in strictly left- to-right order. In the expression w=x+y*z, for example, the subexpression w is evaluated first, followed by x, y, and z. Then the values of y and z are multiplied, added to the value of x, and assigned to the variable or property specified by expression w. Adding parentheses to the expressions can change the relative order of the multiplication, addition, and assignment, but not the left-to-right order of evaluation.

Order of evaluation only makes a difference if any of the expressions being evaluated has side effects that affect the value of another expression. If expression x increments a variable that is used by expression z, then the fact that x is evaluated before z is important."

page 66 : Part I. Core JavaScript ; 4. Expressions and Operators ; 4.7 Operator Overview ; 4.7.7 Order of Evaluation

Aucun commentaire: