Home > Articles > Home & Office Computing > Mac OS X

  • Print
  • + Share This
Like this article? We recommend

Blocks

With Snow Leopard, Apple is adding closures to Objective-C. Unlike most of the parts of Snow Leopard, blocks are being developed in public and are available in the public Clang builds. Blocks don't work by themselves, however; they also need a small runtime library, which is currently private to Apple. Fortunately, third-party implementations already exist. Leopard has a version by Remy Demarest. For anyone who doesn't have a Mac, I've added a version to the Étoilé Objective-C 2 compatibility framework; this version works with the GNU runtime. Just link one of these with your program and pass -fblocks to clang when you compile your code.

Blocks are very similar to inner functions, a GCC extension that provided a very limited form of closure. Unlike inner functions, however, blocks can persist beyond the scope in which they were created, even if they reference variables inside (these variables are copied onto the heap). You can use blocks as an alternative to higher-order messaging.

The syntax for blocks is very C-like, and therefore looks distressingly primitive in an Objective-C program. It's somewhat sad that almost two decades have passed since Brad Cox, the inventor of Objective-C, proposed a much cleaner syntax while working with one of the Apple engineers on the implementation of blocks.

Smalltalk offers two ways of doing a map-type operation. You can either use higher-order messaging, as with Objective-C, or you can use a block:

anArray map someOperation.
anArray map: [ :x | x someOperation ].

The first option has always been possible with Objective-C (although it was only proposed relatively recently). The second requires a block. In Objective-C, it would look like this:

[anArray map: ^(id x){ return [x someOperation]; }];

The argument to this method is a block that takes a single argument, a block, which it invokes like a function:

- (NSArray*)map: (id(^)(id))aBlock
{
        NSMutableArray *result = [NSMutableArray array];
        for (object in self)
        {
                [result addObject: aBlock(object)];
        }
        return result;
}

You can do the same thing with function pointers, but blocks have the advantage of being able to refer to variables in the enclosing scope, so you can write things like this:

int someNumber = [self someNumber];
id array = [anArray map: ^(id x){ [x setIntValue: someNumber]; }];

This is impossible with pure C function pointers, but possible with higher-order messaging. You may also find that this version is easier to read:

id array = [[anArray map] setIntValue: someNumber];
  • + Share This
  • 🔖 Save To Your Account