[Q] Status of blocks

Anthony Hannan ajh18 at cornell.edu
Sat Jan 11 19:09:18 UTC 2003

Ross Boylan <RossBoylan at stanfordalumni.org> wrote:
> My understanding is that blocks don't quite work right in squeak.
> Could someone refresh me about exactly what way they don't work right?
> Apparently they are not "full closures", but that doesn't mean much to me.

Full closure means the block acts exactly like an unnamed method, meaning
it is re-entrant and its args and any new temps are local to it. 
Re-entrant means it can be activated more than once at the same time,
either by multiple threads or the same thread recursively, like a
method.  Local args and temps means each activation will have its own
values for these variables.  Temps declared outside the block that the
block references are shared amongst the different activations like
instance variables of a method.

In current Squeak, blocks are not re-entrant and their args and new
temps are treated like they were declared outside the method.  Meaning
every time you execute a block you are changing the same arg storage
affecting any objects that captured that arg from a previous activation.
 For example, in

	"Collect action blocks to be executed later if necessary"
	actions _ array collect: [:x | [x perform: selector]].

each inner block "[x perform: selector]" created will reference the same
x variable and its value will be the result of its block's last
activation, i.e. x will equal the last element in array for all action
blocks.  For example, evaluate the following example.

	| actions |
	actions _ #(1 2 3) collect: [:x | [x + 1]].
	actions collect: [:b | b value].

Fortunately, there is an easy fix for this in current Squeak.  Send
#fixTemps to the inner block.  For example,

	| actions |
	actions _ #(1 2 3) collect: [:x | [x + 1] fixTemps].
	actions collect: [:b | b value].

The trick is to realize when you need #fixTemps.  You need it when a
block is capturing args of another block.  However, #fixTemps is
overkill because it makes copies of all temps including one that should
remain shared from the outer method.  For example,

	| actions a |
	a _ 0.
	actions _ #(1 2 3) collect: [:x | [x + a] fixTemps].
	a _ 1.
	actions collect: [:b | b value].

With full closures, a would equal 1 when each action block is executed. 
Again, most code won't be so tricky, and there are ways to work around
it, for example,

	| actions a |
	a _ ValueHolder new contents: 0.
	actions _ #(1 2 3) collect: [:x | [x + a contents] fixTemps].
	a contents: 1.
	actions collect: [:b | b value].

So there are ways to work around the non-local args issue.  Likewise,
there are ways to work around the non-reentrant issue, just use a method
instead of a block and use value holders or any other object to hold
shared values.  You resulting code may not be as compact but it will

VI4 makes blocks full closures so you won't need to work around the
above problems.  But VI4 also involves other improvements mainly related
to interpreter speed, which among other things redefines the bytecodes,
and is thus incompatible with the current VM.  I'm thinking of
separating the full closure functionality out so it can be filed into
current Squeak.  It will involve changing the compiler but not the
bytecodes.  Blocks will probably be slower because they will have to use
sends instead of custom bytecodes for certain closure operations.  But
at least it will be compatible with the next Jitter.  Also, the
remaining VI4 project will be free to continue exploring alternative
bytecodes and such.  I bet most people will like this separation.  Is
there anyone who thinks I should keep closures bundled with VI4?

> While I'm on the subject of blocks, I recall that in VisualWorks there
> were big block performance differences depending on how much the
> external environment was referenced (the details are a bit hazy; I
> think it was called open vs closed blocks).  Are there any similar
> performance issues with blocks in squeak?

No not currently, but if I add closures using the current bytecode set
there will be, although I don't anticipate big differences because
everthing is slow anyway (interpreted).  VisualWorks is JIT compiled so
differences like this may be more noticeable.


More information about the Squeak-dev mailing list