Sunday, March 30, 2003

Blocks in Objective-C

Joe Osborn’s OSFoundation framework adds blocks to Objective-C. The context for the block is passed in manually, and the code is specified as a string that’s interpreted at runtime.

Chris Kane mentions that you can do something similar using GCC 3.1’s nested functions and statement expressions. Blocks created in this way have lexical scope, but not dynamic extent, and the syntax is not great.

4 Comments RSS · Twitter

At the risk of exposing my inaptitude for boutique languages, what's the significance of blocks to the Cocoa programmer at large? (And where did the idea originate that the word "block" wasn't already in use?)

Thanks.

This use of “block” originated in Smalltalk, Objective-C’s other parent. Smalltalk blocks are used in many of the same places as C blocks (although they mean different things), so maybe that’s why the same term was used. For example, this C code:

if ( foo == 4 )

{

    printf("bar");

}

else

{

    printf("baz");

}

Might look like this in Smalltalk:

(foo = 4) ifTrue:

[

    ('bar' printOn: stdout)

]

ifFalse:

[

    ('baz' printOn: stdout)

]

Syntactically, they are quite close ([ instead of {). Semantically, a Smalltalk block is like a function (plus context). (foo = 4) returns a boolean object, that object is sent the #ifTrue:ifFalse: message, and it “calls” one of the two blocks depending on whether the boolean was true.

Blocks in Cocoa aren’t as nice as Smalltalk blocks, but they do make certain types of code more elegant. For instance, say you have an array of objects and you want to produce a new array of all the strings in the array. Using OSFoundation’s blocks, you could write it like this:

id strings = [objects select:ocblock(:o | [o isKindOfClass:[NSString class]];)];

-select: is like grep in Perl.

Or maybe you have an array of paths and you want to produce an array of the names of the files:

id names = [paths collect:ocblock(:p | [p lastPathComponent])];

-collect: is like map in Perl.

Finally, if you have an array of NSDecimalNumbers, you might want to sum them:

id total = [numbers inject:[NSDecimalNumber zero]

                      into:ocblock(:sum :n | sum = [sum decimalNumberByAdding:n])];

I don’t know of a Perl equivalent to -inject:into:. (Also, the sum = wouldn’t be necessary in Smalltalk, but it’s in the OSFoundation example, so I included it.)

Of course, you could have done all of this without blocks, but you would have had to write a lot of boilerplate code. The other nice thing is that you can pass around block objects, just as you can pass around function pointers in C.

Oh, one other thing that I should have made clear: ocblock( and ) in Objective-C/OSFoundation are equivalent to [ and ] in the Smalltalk example. [ and ] in Objective-C are like ( and ) in Smalltalk.

Related: MPWFoundation includes Higher Order Messaging (HOM), which uses -forwardInvocation: and trampolines to implement -collect:, -select, etc. The syntax is nice, and the generated code is probably faster than the above two solutions. (It uses IMP caching both for iterating over the array and for messaging its elements.) MPWFoundation is really slick, but not being able to use multiple statements with HOM (like you can with blocks) makes it much less useful than it might be.

Leave a Comment