a = b ne copie rien. Deux noms, un seul objet.a = b copies nothing. Two names, one object.
Le dev venant de Java, Go ou C lit a = b comme « range dans b une copie de a ». En Ruby, c'est faux : une variable ne tient jamais un objet, elle tient une référence vers lui. a = b fait pointer b vers le même objet que a. Tant qu'on ne réassigne pas, muter l'objet par un nom le mute pour tous les autres — et c'est ainsi qu'un tableau « local » se retrouve modifié à distance par un appelant qu'on avait oublié.A dev from Java, Go or C reads a = b as 'put a copy of a into b'. In Ruby, that's wrong: a variable never holds an object, it holds a reference to one. a = b makes b point at the same object as a. As long as you don't reassign, mutating the object through one name mutates it for all the others — and that's how a 'local' array ends up modified at a distance by a caller you'd forgotten.
a = "ruby" # un objet String, quelque part en mémoire b = a # b ne COPIE rien : b et a désignent le MÊME objet a << " loop" # on mute l'objet en place (pas de réassignation) a # => "ruby loop" b # => "ruby loop" ← b a changé sans qu'on y touche a.object_id == b.object_id # => true un seul objet, deux noms
Les deux flèches arrivent sur le même objet. Le réassigner (a = "neuf") ne déplace que la flèche de a ; le muter (a << …) change l'objet que b regarde encore.Both arrows land on the same object. Reassigning it (a = "new") moves only a's arrow; mutating it (a << …) changes the object b is still looking at.
« Est-ce que je mute en place (!, <<, gsub!) un objet qui ne m'appartient pas ? » Avant chaque mutation, demande-toi qui d'autre tient ce même objet. Si la réponse est « l'appelant », tu es sur le point de le surprendre."Am I mutating in place (!, <<, gsub!) an object that isn't mine?" Before each mutation, ask who else holds this same object. If the answer is "the caller", you're about to surprise them.
Ruby n'a pas de « variables qui contiennent » : tout nom est une étiquette collée sur un objet. Plusieurs étiquettes peuvent désigner le même objet — c'est l'aliasing. Tant qu'on ne fait que lire ou réassigner, l'aliasing est invisible et gratuit. Le jour où l'un des détenteurs mute l'objet en place, il devient une source de bugs silencieux — visible partout, attribuable nulle part.Ruby has no 'variables that contain': every name is a label stuck on an object. Several labels can name the same object — that's aliasing. As long as you only read or reassign, aliasing is invisible and free. The day one holder mutates the object in place, it becomes a source of silent bugs — visible everywhere, attributable nowhere.