The Syntax of Objective-C Blocks

Even after writing Objective-C for years it can be tricky to remember the exact details regarding the syntax for blocks. There's a couple parenthesis and a caret. The exact ordering though is easily forgotten and worse yet there appears to be six unique incantations.

Luckily there are actually only two and remember why they are they way they are should help to remember the syntax that next time that you go to use blocks.

Pointers in C

Objective-C is nearly a strict superset of C. Only a few rules have been altered and really to relax a few constraints (such as not enforcing functions to be declared before use if used within an @implementation). What matters most here is that Objective-C uses the exact same syntax for pointers as C does without any exception. Here's a quick refresher of a few example type declarations and an equivalent declaration for a pointer of the same type.

TypePointer to Type
int i;
int *i;
float f[];
float *f[];
char c[][];
char *c[][];
uint8_t *u[];
uint8_t **u[];
struct Foo f;
struct Foo *f;

The pattern is easily recognizable - the language was designed that way - you simply put an asterisk immediately to the name and it becomes a pointer to the type that it was.

Let's try to apply the same logic to the declaration of a function.

float someFunction(int);

If we mimic the pattern we would precede the function name with an asterisk.

float *someFunction(int);

Unfortunately the parse-rules of C are not on our side now. The asterisk is treated as bound to the return type and now we have a function that returns a pointer to a float. It is still a function, that now returns a pointer, instead of it being a pointer to a function itself.

We need a way to tell the compiler that the its rules of precedence do not apply correctly in this instance. How do we tell the compiler to group items differently than is standard? Parenthesis!

float (*someFunction)(int);

Success! We have simply told the compiler exactly how the asterisk should be bound in the expression.

This leads to a simple trick for remembering how to write a function pointer:

Write the function declaration for the type of function that you want to point to and precede the name with an asterisk. Don't forget to add parenthesis to force the compiler to bind the entire type as the pointer instead of the return value.

Following that logic we can easily produce the syntax for the declaration of the type alone, without needing to specify a particular name.

float (*)(int);

This is the declaration of a particular type of function pointer (one that takes an int and produces a float).

Reading a Function Pointer

Remembering a function pointer as a function, plus an asterisk, plus a set of parenthesis should enable you to remember it after applying it a few times (instead of just looking it up, in which case you'll never actually learn it). But there is another way to look at function pointers, which easily applies to all types in general, where you build the type from inside-out.

Here is a type
someFunction
that is a pointer
*someFunction
to a function
(*someFunction)()
that takes an int
(*someFunction)(int)
and returns a float.
float (*someFunction)(int);

This can be helpful for constructing more complex expressions, but requires more subtlety than the previous suggestion for remembering the syntax.

Functional Function Syntax

When a function is treated as a type it can be the value stored in a variable via which it can be passed around like any other value. Thus just like any other type there are 5 situations in which it can appear:

1. Declaration
float (*someFunction)(int);
2. Typedef
typedef float (*my_int_to_float_t)(int);
3. Class Property
@property (assign) float (*function)(int);
4. Function Argument
float applicator(int i, float (*func)(int));
5. Selector Argument
- (float)applyFunction:(float (*)(int))func toInt:(int)i;

It should be apparent that 1, 2, 3, and 4 are all exactly the same. They are all the syntax for the declaration of a function pointer used in 4 different context. The 5th item is actually the exact same syntax as well but with one slight difference.

Each argument in a selector is written with the type in parenthesis followed by the name of the variable. Thus the 5th item is the exact same as the previous 4 except that declares the type without a name, wraps it in parenthesis, and then puts a name after it.

The most important takeaway from all of this is that there is only ONE syntax relating to function pointers. The 4th item could also be written to omit variable names (since they are not required in function declarations).

float applicator(int i, float (*func)(int));
float applicator(int, float (*)(int));

Both of those are equivalent and we see one last time that there is only one syntax at play.

Blocks

Clang 3.5 added support for blocks also known as anonymous functions, closures, or lambdas. The specification focuses on two critical pieces of syntax, the declaration and the definition of blocks.

declaration is an expression that tells the compiler about a type. It tells it in which expressions it can appear and what the semantics of its use are.

definition provides the actual information/implementation of a given symbol.

In the expression int i = 4; the int i part is the declaration and the i = 4 is the definition. A function prototype or an externed constant are both examples of declarations. The actual implementation of a function or the contents of an externed constant are the definitions.

Declaring Blocks

So far we have looked closely at the declaration of function pointers. Let's look at the same 5 uses of blocks as we did function pointers above.

1. Declaration
float (^someBlock)(int);
2. Typedef
typedef float (^my_int_to_float_t)(int);
3. Class Property
@property (assign) float (^block)(int);
4. Function Argument
float applicator(int i, float (^block)(int));
5. Selector Argument
- (float)applyFunction:(float (^)(int))func toInt:(int)i;

The syntax is exactly the same as for function pointers except that the asterisk became a caret. Literally there is no difference. Every expression involving the declaration of a block is identical to an expression with a function pointer of the same signature except with the change that the asterisk becomes a caret!

Thus the actual type of all of the blocks above is

float (^)(int);

and so that is what you end up seeing as the type in parenthesis for the 5th item, the use as an argument-type in a selector.

Likewise, the 4th statement could again be used without variable names in the function and you you two equivalent statements.

float applicator(int i, float (^block)(int));
float applicator(int, float (^)(int));

Defining Blocks

There are only two pieces of block syntax remaining. One of the two is __block which I am not going to discuss here. That leaves only one final piece of syntax, the actual definition of a block. Luckily, this one is the easiest piece of syntax. Consider the caret to be a unary operator that takes a function with no name and produces a block object. It's that simple.

^float(int i) {
 return i * 2.0;
};

Compare it to the equivalent C function.

float aFunction(int i) {
 return i * 2.0;
}

To make it into a block all you do is omit the name, turning it into an anonymous function and pass it to the unary caret operator. Since this produce an object you have to end in a semicolon.

Putting it all Together

That's all there is to it. That is the syntax of blocks and there is nothing more.

Let's look at an example in full to ensure that the syntax sticks.

float (^aBlock)(int) = ^float(int i) {
 return i * 2.0;
};

The left side of the equals, the declaration, is just like a function pointer in C except that the asterisk became a caret. And remember that the syntax of a function pointer is just that of the function with an asterisk and a set of parenthesis to enforce the binding of the pointer to the type.

The right side of the equals, the definition, is the unary caret operator applied to an anonymous C function.

So, here's all the block syntax there is.

1. Declaration
float (^someBlock)(int);
2. Typedef
typedef float (^my_int_to_float_t)(int);
3. Class Property
@property (assign) float (^block)(int);
4. Function Argument
float applicator(int i, float (^block)(int));
5. Selector Argument
- (float)applyFunction:(float (^)(int))func toInt:(int)i;
6. Definition
^float(int i){ ... };

There appears to be six unique variants to remember but there aren't, there are two, each of which is easily deducible if you remember where the syntax comes from.

Coping with and Learning Block Syntax

If you go and look up block syntax every time that you need to use it, then you'll never remember it. Instead try to work through it and remember the reasoning behind it. If you do need to reference the syntax then come do it here since it will be a reminder of how you yourself can recall it in the future.

As you begin to try to digest this syntax, allow me to leave you with something absurd. What would it look like to have a block that returns a block?

int(^(^scalingFactory)(float))(double) = ^int(^(float a))(double) {
  return ^int(double b) {
    return a * b;
  };
};

Good luck trying to apply the syntax rationale discussed here to this particular situation. Sometimes the embedding of types becomes so unruly that you should just use a typedef and call it a day.

typedef int (^my_double_to_int_t)(double);

my_double_to_int_t (^scalingFactory)(float) = ^my_double_to_int_t(float a) {
  return ^int(double b) {
    return a * b;
  };
};

Don't let the syntax block you. Learn it. Apply it. Party.