Hi all,
this feels like a FAQ, but there have been so many similar decades-old posts on this list that I hope you forgive me for possibly re-posting this. :-)
Simple example:
Object subclass: #Dummy
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'as yet unclassified'
Dummy>>listen
Smalltalk when: #plonk evaluate: [nil halt].
Dummy new listen.
Smalltalk garbageCollect.
self assert: Dummy allInstances isEmpty. "fail! our Dummy object is still referenced"
chasePointers reveals that, as expected, our dummy is still captured inside the BlockClosure's receiver and outerContext. I have learned that I can use MessageSends and WeakMessageSends instead of a block closure in this particular purpose but am curious why clean blocks have to capture the receiver anyway. From as I understand FullBlockClosure comment, this would not be necessary, and indeed:
Dummy>>listenClean
Smalltalk when: #plonk evaluate:
([nil halt]
outerContext: nil;
receiver: nil;
yourself).
Dummy new listenClean.
Smalltalk garbageCollect.
self assert: Dummy allInstances = 1. "pass! just the previous reference"
Smalltalk triggerEvent: #plonk. "still works"
The only caveat is that this partially breaks BlockClosureInspector.
So, long story short, could the compiler could indeed detect clean blocks and emit a special pushCleanBlockClosure instruction that does not unnecessarily reference the receiver? Or would there be any existing behavior that actually *relies on* keeping the receiver in the memory due to this? Do I assume correctly that clean blocks be possible and desired and are just not implemented at the moment? Asking further, could this even work for non-clean blocks (unless they have a non-local return or refer to self) thanks to the invention of closure vectors? This seems to work as well:
Dummy>>listenClean2
| w |
w := World.
Smalltalk when: #plonk evaluate:
([w halt]
outerContext: nil;
receiver: nil;
yourself).
Asking because this can introduce severe memory leaks (if this is an appropriate term inside the image) and I think there is a lot of unnecessary metaprogramming with MessageSends and WeakMessageSends due to this in the Trunk. First, I would like to assure my understanding of the situation and second, I am dreaming of a future where blocks can rule all this. Plus, I'm very thankful there's no need for [](){} in Squeak. :-)
Best,
Christoph
---
Sent from Squeak Inbox Talk