Basic Blocks

Now that Snow Leopard has shipped, the Blocks Programming Topics is available from Go have a read; it is a great primer for Blocks.

This post is focused solely on the core syntax of Blocks; declaring a block and calling a block.

Blocks are closures for C.

That is, a block is an anonymous inline collection of code that (Note: lexical scope means function or method or {}-surrounded collection of statements:

  • has a typed argument list just like a function
  • has an inferred or declared return type
  • can capture state from the lexical scope within which it is defined
  • can optionally modify the state of the lexical scope
  • can share the potential for modification with other blocks defined within the same lexical scope
  • can continue to share and modify state defined within the lexical scope [the stack frame] after the lexical scope [the stack frame] has been destroyed

Blocks is available in GCC and Clang as shipped with the Snow Leopard Xcode developer tools. The Blocks runtime is open source and can be found within LLVM’s compiler-rt subproject repository. Blocks have also been presented to the C standards working group as N1370: Apple’s Extensions to C (which also includes Garbage Collection).

As Objective-C and C++ are both derived from C, Blocks are designed to work fine with all three languages. Thus, the syntax reflects this goal.

A block is introduced using the ^ — the caret — character. The ^ was chosen as it had no unary form (and C++ couldn’t operator overload it).

For the purposes of an excruciatingly simple example, how about a block that multiplies two numbers?

Declaring a variable that could refer to such a Block would be done with something akin to a function pointer:

    int (^multiplyIt1)(int, int);

Of course, if one were to have a slew of different blocks that could multiply two ints in a slew of novel and innovative ways, the type of the Block could be captured in a typedef:

    typedef int (^MultiplyItBlockType)(int, int);
    MultiplyItBlockType multiplyIt2;

Capturing a bit of code — a unit of work — in a block and assigning it to one of the above variables is as follows:

    multiplyIt1 = ^(int x, int y) { return x * y; };

Since a block typed variable is simply a reference to a chunk of code — a unit of work — then simple assignments work, too:

    multiplyIt2 = multiplyIt1;

To execute a Block, it is called just like a function:

    int result = multiplyIt1(7,6);
    printf("multiplyIt1(7,6) = %d\n", result);

Which spits out multiplyIt1(7,6) = 42.

Just like function pointer syntax, it is possible to declare types that are rather more complex. Blocks that take blocks as arguments or return blocks? Sure. Works fine. Functions that return arrays of blocks that return arrays of function pointers? Yup. Compiler will correctly eat that too.

Whatever C perversion you can imagine, Blocks should play nicely. There are some rough edges with certain C++ perversions, though.

Embracing typedefs can reduce the insanity factor.

Objective-C is a simple set of extensions to C. Whatever C provides, Objective-C does to. And this includes blocks.

Defining a method that takes a block as an argument works just like declaring a method that takes a function pointer as an argument:

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;

The above is one of the many new bits of API in Snow Leopard that use Blocks.

A style tip; when declaring a function or method that takes a Block as an argument, always try to limit it to just one Block argument and always make said Block argument the last argument. It makes the code easier to read and write at the call site:

    NSArray *frameworks = [NSBundle allFrameworks];
    [frameworks enumerateObjectsUsingBlock:^(id aFramework, NSUInteger i, BOOL *stop) {
        NSLog(@"Framework path: %@", [aFramework bundlePath]);

Just like all other C types, Blocks can be used as instance variables and/or properties.

And there you have Basic Blocks. Next up? The innards of Blocks…

12 Responses to “Basic Blocks”

  1. @bbum’s Blocks primers » señor taco’s travels says:

    [...] Blocks Basics [...]

  2. Dan says:

    Sorry, but after looking through several docs and posts like this, I can’t find the answer to the most important question about blocks for me: Will code I write using blocks, compiled and built with Xcode 3.2, execute on 10.5 (and 10.4)? While discussions about blocks are centered around 10.6′s release, nothing seems to say that some special part of 10.6 is required for blocks to execute when compiled (unlike GC in 10.5, where it was clearly stated that 10.4 lacked the runtime support). Nothing I could find in the canonical documentation nor original posts about blocks. Unfortunately, I don’t get to choose what OS versions my work must support.

  3. bbum says:

    Blocks aren’t officially supported anywhere but Snow Leopard. Beyond a Blocks compatible compiler, you also need the Blocks runtime. It is tiny and open source.

    Folks have ported it to Leopard (Tiger shouldn’t be hard) and the iPhone.


  4. Bob Peterson says:

    This looks a lot like C# lambda expressions (well, like any lambda expression). Are there any differences that might explain why they didn’t just call it that instead of overloading the word “block”?

  5. bbum says:

    Lambdas, closures, and Blocks are all semi-synonymous. They do all represent a chunk of code that can capture some state and can be passed as a form of data.

    Lambdas are most often associated with capturing an expression, often to be used as a filter on a collection. In Python, a lambda is truly one single simple expression. The proposed lambdas in C++ are effectively a compile time only expression oriented feature.

    Blocks are designed to capture both simple expressions for the purpose of collection filtration, callback bindings, etc… as many of the APIs in Snow Leopard demonstrate. However, they are also designed to capture full units of work in the form of entire chunks of code. That is, a Block is often a chunk of code that one might normally find as the implementation of a method or a function.

    Thus, the label lambda and closure were rejected because they seemed to limit people’s perception of what the feature was capable of or how it could be appropriately used. Blocks didn’t seem to carry quite so much comp-sci preconceived baggage.

    Blocks also implies “building blocks” and it is quickly becoming the case that many modern Cocoa applications are composed of a bunch of Blocks that do work concurrently via GCD.

  6. Brian Mastenbrook says:

    “Thus, the label lambda and closure were rejected because they seemed to limit people’s perception of what the feature was capable of or how it could be appropriately used.”

    Lambda limit’s people’s perception? “Lambda: The Ultimate ” – that lambda? If Python’s totally broken closures are to blame for this, GvR ought to have actually removed them and spared us all the trouble.

    “Blocks didn’t seem to carry quite so much comp-sci preconceived baggage.”

    I guess being a Lisper is a bit like being a groundhog. Every year, you stick your head out, sniff around, check the blogs, and figure we’re all in for another year of ignorance and stupidity. Wake me up again next year and I’ll tell you whether or not we’ve caught up with where programming language research was in 1980. Probably not, as long as comp-sci is “preconceived baggage”.

    I’m not saying that “block” is an indefensible choice of name – in fact it was probably the best choice in the specific context of Objective C given its Smalltalk heritage. But this line of argument induces Hulk rage in me. The same circular we-can’t-do-anything-too-academicish reasoning is why we’re all circling the drain of the ’70s over and over again.

    (Actually that’s not quite fair: Microsoft seems to be dragging everyone headlong into the 1990s with F#. It’s really Apple who’s behind the times here.)

  7. Brian Mastenbrook says:

    My typo in the last comment (“limit’s” instead of “limits”) also induces Hulk rage in me. Sorry.

  8. bbum says:

    Heh. No worries. Certainly, whatever word was chosen, someone would get frothy about it. That your post has “I’m not saying that ‘block’ is an indefensible name” is certainly a point in favor of Blocks.

    The reality, unfortunately, is that in the modern, commercial, software development environment, Lisp and SmallTalk are pretty much irrelevant.

    The buzz goes to Java’s, Ruby’s, and — to a lesser extent these days — Python’s oft [sometimes poor] wheel reinvention, with C# rising and the various functional languages off in a corner making a lot of noise banging their immutable sticks together.

    Of course, many of us Objective-C developers froth at the mouth when the Java kids claim that Obj-C is just a weirdass derivative of Java when the exact opposite is true! Then the SmallTalkers crawl out of the wood work and ask us to pipe down, get off their damned lawn, and come back when Objective-C can redefine true to false.

    Meanwhile, the Lisp and SmallTalkers all rage about Been There, Done That, Wake me when you have something new.

    Of course, if you want to go all hippie on it, [Lisp and the] Art of the Metaobject Protocol must be mentioned.

  9. bbum says:

    (that was, btw, a large pile of “don’t take this seriously”. :) )

  10. Brian Mastenbrook says:

    Hey, I actually said that it was probably the best choice in context too! :-) I was just annoyed by the concept that Python has so dirtied the name of `lambda’ that it couldn’t be used.

  11. Grand Central Dispatch and Blocks Links. | Tyler Weir says:

    [...] [...]

  12. ios blocks 相关存档 | 右舷 says:

    [...] Block Basics by Bill Bumgarner [...]

Leave a Reply

Line and paragraph breaks automatic.
XHTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>