Aha! How to get rid of Blocks in Smalltalk.

David Farber dfarber at numenor.com
Thu Apr 20 05:31:51 UTC 2000


First of all, let me apologize if what I am about to propose is not a novel
idea. I've certainly never heard anyone propose anything like it.

Second, I must confess that this idea came to me while I was under the
influence. The substance in question was Jef Raskin's excellent new book,
"The Humane Interface". I strongly recommend that anyone on the list that
has not bought and read this book do so ASAP.

Now, to the heart of the matter: I have realized how Blocks can be removed
as a language construct in Smalltalk without giving up functionality or
power of expression.

Why remove Blocks? Blocks have long been one of my biggest qualms with
Smalltalk (perhaps second only to the lack of namespaces). I am sure that
my original uneasiness came from having to get used to the wierd flow
control contructs. But even once I was used to 'aBoolean ifTrue: []
ifFalse: []' and thought it was so cool that flow control could be left out
of the base language and created, on demand, from simple message passing, I
was still not entirely convinced that Blocks were The Right Thing To Do.

Then, last night, in less than an hour after I had just finished Raskin's
new book it hit me: Blocks are almost always unique functional units by
virtue of grouping message sends. But Smalltalk already has a mechanism for
creating new functional units by grouping message sends; it is called a
Method. Having two ways to do the same thing violates the principle of
monotony. As soon as my beef with Blocks was expressed in these terms, I
knew for certain that 1) Blocks had to go and 2) they could be replaced
with regular methods and message sends and not be missed.

To put what I've just said into a (kind of) concrete example, what I am
proposing is the following:

WITH BLOCKS

aCollection do: [ :each | a foo. b bar. self doSomethingWith: a with: b
with: each].

WITHOUT BLOCKS

newMessage := MessageSend send: 'doThisWith:with:with:' to: self with: #(a b).
aCollection do: newMessage.

<METHOD>
doThisWith: a with: b with: c

  a foo.
  b bar.
  self doSomethingWith: a with: b with: c.
 
(NOTE: To obviate the need for the Collection do: method to be rewritten,
MessageSend would implement value: by just appending the object passed to
the arguments array. I made up the MessageSend class just to make my point
as cleanly as possible. The method send:to:with:super: in ContextPart
actually does what I am describing.)

To try and explain my idea one more time, all I have done is: 1) put the
message sends formly grouped in the Block into their own method. 2)
Explicitly created a message send. 3) Passed the message send instead of
the Block.

I don't see anything that cannot be done with this scheme that can be done
with blocks. The advantage is that the language is now simpler, having
removed a construct that, in the final analysis, didn't really contribute
anything.

Now, having to always explicitly create the message send as I did in the
example above could lead to some serious brain damage; it is really quite
cumbersome. So, what we need is a shorthand for creating explicit message
sends just as #() is shorthand for Array creation. I don't have any
definite ideas here, but one possiblity would be to re-use the old block
semantics.

  [ :arg3 | receiver message: arg1 with: arg2 with: arg3]

The example given above would now look like:

  aCollection do: [ :each | self doThisWith: a with: b with: each].

The above is an explicit message send, NOT a block. You could not, for
instance, try to stuff a second message send in there or chain message
sends with ;. That would be creating a new message grouping and that is
what methods are for. The advantage here is that the new language
specification is a proper subset of the old; you could file this into any
current Smalltalk implementation and it would run. It should also be fairly
straightforward to translate from the old to the new. The biggest drawback
that I can see to this is that users who were presented with the change but
not the rationale would probably not think to make a new method to take the
place of the message grouping that would have been put inside the block.

Well, I hope I have explained my idea clearly enough. Let me know what you
think. I, for one, am estatic; I've finally figured out why I've always
been uncomfortable with blocks and how I can get rid of them! At least,
until someone bursts my bubble. :)

david

--
David Farber
dfarber at numenor.com





More information about the Squeak-dev mailing list