Michaell's been having some fun with context stitching. Cool stuff. One of the things I bugged him to look at didn't quite turn out all the way though. A while ago, there was a thread on one of the Smalltalk mailing lists about telling when a process is done, from another process. And I proposed a similiar technique as what Michaell has used for his onExitDo:. Bascically, walk backwards along the processes context chain until you get near the beginning, and then insert hooks to do whatever you want. It was a good post, and I feel a bit like Ellen Feis not being able to locate it.
Either way, both approaches have a problem. Consider the following naive example:
countDown :=
[10 to: 1
by: -1
do:
[:n |
n out.
(Delay untilSeconds: Time secondClock + 1) wait].
'Lift Off!' out]
fork.
#('Michaell' 'Travis' 'Terry' 'David')
do: [:each | countDown onExitDo: [(each , ' applauds.') out]]
It won't work. It'll UHE. Why? I mean besides the fact that I used those #out messages which are in my image, but not yours (load Out from the Open Repository, it so unclutters Transcript spewing code). If we modify the code slighlty:
...
fork.
Processor yield.
#('Michaell' 'Travis' 'Terry' 'David')
...
now it will work. The problem is that in my naive example, the countDown process has never come alive yet when I'm registering the exit blocks. So it has no context chain to analyze and restitch with hooks to do our exit actions. Luckily, Smalltalks awesome introspection abilities aren't limited just to context objects. BlockClosure are equaly extensible and introspectable. Basically, the version of BeforeYouLeave just published does just that. It peeks inside the block that will eventually be run. Said block is the process execution machinery, and it has a reference to the block you gave it to run. So we just replace that reference with a new block, one that runs the original and ensures the exit condition. And this of course can be done repeatedly, and they restitching of the blocks copied values just nests nicely.