Talking Meta

Meta talk about Smalltalk, Seaside, Magritte, Pier and related things.

Continue and Break in Ottawa

The second part of the Superpowers Workshop of the Ottawa Smalltalk user’s group caught my interest. The attendees are discussing on how to implement break and continue in Smalltalk.

Unfortunately the quality of the video was not good enough to be able to steal their example, so I had to build my own. The commented parts should trigger the well known loop operations and continue with the next iteration of the loop, respectively break the execution of the loop.

1 to: 5 do: [ :index |
index = 2
ifTrue: [ " continue " ].
index even
ifTrue: [ " break " ].
Transcript show: index; cr ]

The above example exercises the two hypothetical constructs. If you execute the code in your brain you should print out the numbers 1 and 3 on the transcript.

The first possible solution that comes to my mind are exceptions. Smalltalk has very powerful exceptions that can do all kind of magic things, but here we just need to signal and catch them at the right place. I created two new exception classes ContinueLoop and BreakLoop, then I put a handler inside the loop to continue, and a handler outside the loop to break. This gives us the first working solution. Admittedly it looks very ugly:

[ 1 to: 5 do: [ :index |
[ index = 2
ifTrue: [ ContinueLoop signal ].
index even
ifTrue: [ BreakLoop signal ].
Transcript show: index; cr ]
on: ContinueLoop
do: [ :err | ] ] ]
on: BreakLoop
do: [ :err | ]

Somebody of the Ottawa Smalltalk user’s group suggested to use continuations and they eventually come up with a pretty complicated solution. In fact, if you have the Seaside classes loaded in your image, the use of continuations provides a pretty strait-forward solution to the problem. You wrap the complete loop into a continuation to break, and the body of the loop in a continuation to continue. Evaluating the block arguments break and continue jumps right to the place after you created the respective continuations and resumes execution from there. This gives us the expected behavior:

Continuation currentDo: [ :break | 
1 to: 5 do: [ :index |
Continuation currentDo: [ :continue |
index = 2
ifTrue: [ continue value ].
index even
ifTrue: [ break value ].
Transcript show: index; cr ] ] ]

The solution is quite readable, but it basically uses a sledgehammer to crack the nut. Also continuations are pretty heavyweight to use in tight loops like this, because they essentially create a snapshot of the complete execution stack. And in this example we are not interested into the stack at all, we just want to jump back to the place where the continuation was defined. Luckily jumping back is something plain old Smalltalk blocks can do as well:

withEscaper: aBlock
aBlock value: [ ^ nil ]

This small helper methods evaluates aBlock and passes another block into it that returns nil. It is important to note that a return in Smalltalk always returns from the lexical scope, that means it returns from the method the return was defined in. In this example, evaluating the block [^ nil ] returns from the method #withEscaper:. Of course, this only works if the method, #withEscaper: is still on the execution stack (if not, we had to use continuations).

We can use the above helper method to implement the final version of our loop. This time without using magic, but simple and fast Smalltalk blocks:

self withEscaper: [ :break | 
1 to: 5 do: [ :index |
self withEscaper: [ :continue |
index = 2
ifTrue: [ continue value ].
index even
ifTrue: [ break value ].
Transcript show: index; cr ] ] ]
Posted by Lukas Renggli at 20 October 2009, 9:13 pm with tags smalltalk, continuation 4 comments link

Pharo by Example

The open-source book Pharo by Example has been announced. It is a new, improved and adapted version of Squeak by Example to Pharo, the new Smalltalk that is quickly approaching its 1.0 release. One of the particularly exciting additions to the book is the chapter Seaside by Example.

Posted by Lukas Renggli at 18 October 2009, 11:15 pm with tags pharo, smalltalk, seaside comment link