[squeak-dev] Questions about FullBlock closures

Eliot Miranda eliot.miranda at gmail.com
Sat Feb 11 18:48:00 UTC 2023

Hi Jaromir,

> On Feb 11, 2023, at 5:09 AM, Jaromir Matas <mail at jaromir.net> wrote:
> Hi,
> Two questions:
> 1) When I do:
> BlockClosure allInstances size "---> 66"
> I always get 66 instances of BlockClosure, all of them probably related to the UI (as far as I can tell).
> Q: Why do we have those closures as instances of BlockClosure and not FullBlockClosure? (just trying to understand)

Blocks can outlive their enclosing activation:

        GlobalVariable := [‘this is a value returned by a block whose enclosing activation has been returned from’].

self captureBlock. GlobalVariable value

And GlobalVariable outerContext sender isNil

If a block can outlive its outer activation it can outlive the recompilation of its method.  Unless such global variables are reinitialized after the system is recompiled obsolete methods (and indeed transitively obsolete classes) can be retained.

Look at SystemNavigation unboundMethods and obsoleteClasses fir code that ferrets out these stale references. 

> 2) When I do:
> (FullBlockClosure allInstances select: [:each | each outerContext isNil]) size "---> 0"
> I always get zero; this means there are no closures without the outer context set. However, the class comment says:
> FullBlockClosure: [...] outerContext can be either a Context or nil.
> Q: When would it make sense to use a FullBlockClosure with nilled outer context?

The notion is “clean blocks”. Blocks can close over the receiver, arguments, and local temporary variables if the methods (& blocks) in which they are nesting.  Further, a block may contain an up arrow (method) return (*). These returns attempt to return to the sender of the home context (the context for the method activation). And if course a block can contain both an up arrow return and close over self & outer arguments/variables. These three kinds of blocks are not clean.

Blocks which make no such references to their outer context are clean.  Clean blocks refer only to literals and their own arguments and local temporaries.  Such blocks are seen used as, for example, sort blocks:
    [:a :b| a asInteger < b asInteger]

In this case there is no need for the outerContext to exist and the compiler could be upgraded to instantiate them at compile time, included as literals in the literal frame.  I believe Pharo has so extended their compiler.  Note also that this is independent of the bytecode set.  (I’m not 100% sure but at least in theory) Clean FullBlockClosures could be created for V3PlusClosures methods since the value primitives are not specific to the bytecode set.

(*) rewrite the above example as

        GlobalVariable := [ ^ ‘this is a value returned by a block whose enclosing activation has been returned from’].

self captureBlock. GlobalVariable value

and we now get a CannotReturnError.

In blue book Smalltalk-80 it is possible to do a “sideways return”.  This is where a block is forked into another process and the up arrow return done from within that (or some nested) block in the other process.  This is clearly a very bad thing (tm), and is explicitly banned in all modern Smalltalk implementations, Cog included.

> No such situation in the system?

Not yet. We would have to modify the compiler.  The performance gains are small in general but large in specific cases.  The only real downside is that, eg in the debugger, one cannot tell in what context the clean block was created.  This may be confusing, analogously to your curiosity about the origins of the non-full blocks persisting in the system.

> I wonder: if we used a FullBlockClosure with outerContext == nil, how would then methods like Context >> home work? They assume 'closureOrNil outerContext' is not nil and would fail, if I understand correctly.

They won’t and can’t. They must answer nil or raise an error.

> Am I missing something/confused??

You’re asking important questions that every Smalltalk vm and/or bytecode compiler programmer should understand.  This stuff used to be discussed/taught up front.  I hope that having read and thought through the above you now feel you’re no longer missing something.

>  Many thanks for any help,

Here’s an exercise for you. Find out where and how in the Cog/OpenSmalltalk VMMaker source the protection against sideways returns is implemented.

>  best,
> Jaromir

_,,,^..^,,,_ (phone)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20230211/5005f964/attachment.html>

More information about the Squeak-dev mailing list