Le bloc n'emporte pas que du code. Il emporte l'endroit où il est né.A block carries more than code. It carries the place it was born.
On a capturé un bloc dans un objet (proc, lambda). Voici ce qu'on n'avait pas dit : cet objet n'emporte pas que les instructions — il emporte les variables locales qui l'entouraient à sa naissance. La lambda renvoyée par make_counter continue de voir count, et de le modifier, longtemps après que make_counter a rendu la main. C'est une closure : un bloc qui se referme sur son environnement.We captured a block in an object (proc, lambda). Here's what we hadn't said: that object carries more than the instructions — it carries the local variables that surrounded it at birth. The lambda returned by make_counter keeps seeing count, and mutating it, long after make_counter has returned. That's a closure: a block that closes over its environment.
def make_counter count = 0 # une variable locale à make_counter -> { count += 1 } # la lambda VOIT count, et le garde end c = make_counter # make_counter a fini, count "devrait" disparaître… c.call # => 1 c.call # => 2 — count survit, et se souvient c.call # => 3 d = make_counter # un AUTRE compteur, son propre count d.call # => 1 — indépendant de c
Deux appels à make_counter donnent deux count séparés. Chaque closure emporte son propre environnement — pas une copie : les variables elles-mêmes, vivantes, pas figées.Two calls to make_counter give two separate counts. Each closure carries its own environment — not a copy: the variables themselves, alive, not frozen.
« Ce comportement, je le passe en bloc — et il emporte avec lui les variables qu'il voit. » Quand tu confies un bloc, demande-toi : de quoi se souvient-il ?. C'est ce qui le rend puissant (un compteur, un cache, une config capturée) et dangereux (une variable partagée, un gros objet retenu en mémoire)."This behavior, I pass it as a block — and it carries with it the variables it sees." When you hand over a block, ask: what does it remember?. That's what makes it powerful (a counter, a cache, a captured config) and dangerous (a shared variable, a big object retained in memory).
On a vu le bloc confié (№ 1) puis capturé en objet (№ 2). Reste sa vraie nature : un bloc n'est pas un bout de code isolé, c'est du code + son contexte. Comprendre la capture, c'est expliquer d'un coup la puissance des itérateurs, des callbacks et des DSL — et la classe de bugs la plus déroutante de Ruby.We've seen the block handed over (№ 1) then captured as an object (№ 2). What remains is its true nature: a block isn't an isolated piece of code, it's code + its context. Understanding capture explains, at once, the power of iterators, callbacks and DSLs — and Ruby's most baffling class of bugs.