Robert Withers wrote:
Another point. Jesse Welton already pointed out that objects are not copied by closures. If two closures refer to same object through their variables, changes made using one closure will be visible through another. it is important that not only objects are not copied, the bindings are not copied as well. Two closures created within the same environment see the same bindings, so changes done to a variable of that environment from one closure are visible from another. For example:
| cell | ^Array with: [:arg | cell := arg] with: [cell]
-- ??? Really?? This surprises me. I thought that a closure would have it's own binding seperate from any other binding. This is different that two bindings holding the same reference and changing the internal state of that reference. Aren't you saying that two bindings pointing to the same reference and one changes the reference, then the other binding will also have a changed reference?
Yes, this is exactly right. This is necessary to allow (among other things) assignments to propagate upwards. Consider:
| sum | sum := 0. 1 to: self length do: [ :i | sum := sum + self at: i ]. ^sum
In order from something like this to work, "sum" must name the same reference both within and without the block.
-Jesse
Jesse Welton wrote:
Robert Withers wrote:
Another point. Jesse Welton already pointed out that objects are not copied by closures. If two closures refer to same object through their variables, changes made using one closure will be visible through another. it is important that not only objects are not copied, the bindings are not copied as well. Two closures created within the same environment see the same bindings, so changes done to a variable of that environment from one closure are visible from another. For example:
| cell | ^Array with: [:arg | cell := arg] with: [cell]
-- ??? Really?? This surprises me. I thought that a closure would have it's own binding seperate from any other binding. This is different that two bindings holding the same reference and changing the internal state of that reference. Aren't you saying that two bindings pointing to the same reference and one changes the reference, then the other binding will also have a changed reference?
Yes, this is exactly right. This is necessary to allow (among other things) assignments to propagate upwards. Consider:
| sum | sum := 0. 1 to: self length do: [ :i | sum := sum + self at: i ]. ^sum
In order from something like this to work, "sum" must name the same reference both within and without the block.
ugh! This of course makes sense from a usability standpoint but that takes me back to:
Method | answer | answer := Array new: 5. 1 to: 5 do: [:i | answer at: i put: [:arg | arg * i]]. ^answer
Since we are 2 levels deep, each time through the loop we have a different binding for i, so each inner block gets a seperate binding. If this was:
Method | answer i | answer := Array new: 5. i := 1. answer at: i put: [:arg | arg * i]]. i := 2. answer at: i put: [:arg | arg * i]]. i := 3. answer at: i put: [:arg | arg * i]]. i := 4. answer at: i put: [:arg | arg * i]]. i := 5. answer at: i put: [:arg | arg * i]]. ^answer
Then all five blocks would have i = 5. Is it so?
-Rob
-Jesse
squeak-dev@lists.squeakfoundation.org