This post is part of an ongoing series about Affordances and Programming Languages.

Blocks (a.k.a. lambdas, closures, or block closures) are very interesting constructs that have a profound impact on the kinds of solutions we build in a programming language. Different languages support them (or not) in different ways and at different levels.

I’m most familiar with blocks in Ruby and Smalltalk, so I’ll focus on those two languages here, but I will note that C++ just added official support for lambdas in C++11, and Lisp has had lambdas for as long as I’ve been familiar with the language (20+ years).

When I started learning Ruby after having done Smalltalk for many years, I found Ruby’s blocks very familiar and comforting. However, there are some differences in how blocks are implemented that result in different affordances, and thus different idioms.

In Visualworks Smalltalk, blocks are instances of BlockClosure, and so are first-class objects with their own API. There is a literal syntax for creating blocks using square brackets.

Smalltalk blocks can be used just like any other object: You can create them, pass them as arguments to messages, store them in variables, and send messages to them. For example, you can easily time or profile some code by wrapping it in a block and sending a message to it:

Timing and Profiling in Smalltalk
[self doSomething] timeToRun.
[self doSomething] timeProfile.

Like Ruby, Smalltalk uses blocks for enumerating collections. One of the key differences from Ruby blocks is that you can easily pass as many blocks as you like to a method. Because of this, Smalltalk’s version of #detect:ifNone: is cleaner than Ruby’s:

#detect:ifNone
people detect: [:each | each name = 'Fred'] ifNone: [Person named: 'Fred']
:detect in Ruby
notThere = lambda { Person.new("Fred") }
people.detect(notThere) { |p| p.name == 'Fred' }

I suspect that a lot of Ruby programmers don’t even know that :detect (a.k.a. :find) takes the optional ifNone parameter.

Another advantage to being able to pass multiple blocks to a method is that blocks can be the key element in flow control. Smalltalk has no built in operators for loops and conditionals; everything is done using objects, messages, and blocks.

Smalltalk Flow Control
self someCondition
ifTrue: ["handle the true case"]
ifFalse: ["handle the false case"].
[self someCondition] whileTrue: ["loop body"].
1 to: 10 do: [:i | "Do something with i"].

Blocks are also the foundation of Smalltalk’s exception handling:

Exception Handling in Smalltalk
[self doSomething] on: Error do: [:ex | "handle the error"].
ws := 'myFile' asFilename writeStream.
["work with myFile's contents"] ensure: [ws close].

Since blocks are first-class objects in Smalltalk, you can do some very clever things. For example, the Assets package in Visualworks Smalltalk implements the idea of a CachedBlockClosure, or #once block. If you send #once to a block, the value of the block is computed and the block is changed into an instance of CachedBlockClosure containing the cached value. Sending #once to the CachedBlockClosure simply returns the cached value, rather than recomputing it. In Assets, this is used to construct and cache icons and such using only Smalltalk code.

In Ruby, a block can be passed to any method simply by appending the block to the message send, either using curly braces or do ... end. There is no need to explicitly list the block parameter in the argument list unless you need to pass it on to another method. Normally, the block is just an extra, implicit parameter to the method. The method may or may not choose to make use of the block.

Block Usage in Ruby
object.do_something(1, 2) { self.buckle_my_shoe }
object.do_something(3, 4) do
self.shut_the_door
end

Blocks in Ruby are not first-class objects with their own API, but they can easily be converted to Procs which are. In order to pass multiple blocks into a method, all but one of them need to be turned into a Proc or lambda first, as in the :detect example above.

Ruby’s blocks are used a lot for configuration and customization, as well as for providing resource acquisition/release wrappers around code. For example:

Files in Ruby
File.open('myFile') do |file|
# work with myFile's contents
end

There’s no reason Smalltalk’s blocks couldn’t be used this way, but there tends to be less of this pattern in Smalltalk code for some reason.

Ruby provides the block_given? method that allows a method to determine if a block was passed or not. Smalltalk has no such facility; if a method takes a block, then that block must be passed, even if it doesn’t do anything.

block_given? in Ruby
def my_method
# ...
yield(self) if block_given?
#...
end

I’ve outlined some of the differences between Ruby and Smalltalk blocks here. There are others, but overall there is a different “feel” to how blocks are used in the two languages. There is enough similarity to make them feel familiar, but the two languages have developed distinct usage patterns around blocks.

The idiomatic use of blocks in each of the languages seems very consistent with the rest of the language, but I think that is because blocks are a such a large contributor to the feel of each language. Both Smalltalk and Ruby are largely designed around their block implementations, and so each has developed its own personality because of them.