Apple "adds closures to C" in Mac OS X 10.6

(via Ars Technica's review of Mac OS X 10.6)

Apple's version of GCC in Snow Leopard, its new operating system, has a C extension that looks like closures. I'm not sure whether to be marveled that C programs will get lambdas, or appalled that someone will have to figure out manual memory allocation bugs in these. It seems like Apple is moving towards LLVM for its compiler toolchain, and I imagine this extension requires the use of LLVM.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

LLVM not required

The article states that it's supported by all of Apple's compilers, so LLVM is not required.

Article a bit confused

The examples are terrible so it isn't clear to me exactly what they added but they would be totally senseless unless they added closures.

Checking around it seems Apple are adding closures as part of the Grand Central Dispatch ( effort to make better use of multiple cores.

Rules governing memory

the rules governing automatic and static variables, and so on are all still in full effect. Plus, now there's a whole new set of rules for how blocks interact with each of these things. There's even a new __block storage type attribute to further control the scope and lifetime of values used in blocks.

I'd like to see this list of rules governing interaction of blocks with automatic and heap memory. I'm curious as to how, and to what degree, they tackled the upwards funarg problem... and to what degree variables bound within a block are mutable.


Language Specification for Blocks

The compound statement body establishes a new lexical scope within that of its parent. Variables used within the scope of the compound statement are bound to the Block in the normal manner with the exception of those in automatic (stack) storage. Thus one may access functions and global variables as one would expect, as well as static local variables. [testme]

Local automatic (stack) variables referenced within the compound statement of a Block are imported and captured by the Block as const copies. The capture (binding) is performed at the time of the Block literal expression evaluation.

The lifetime of variables declared in a Block is that of a function; each activation frame contains a new copy of variables declared within the local scope of the Block. Such variable declarations should be allowed anywhere [testme] rather than only when C99 parsing is requested, including for statements. [testme]

Block literal expressions may occur within Block literal expressions (nest) and all variables captured by any nested blocks are implicitly also captured in the scopes of their enclosing Blocks.

Const binding

Use of constant binding is a reasonable decision, certainly. Given the semantics of C/C++, this is likely one of the most-reasonable options. But it does mean block semantics are not the same as code found in the body of a 'for' loop and such. E.g. there are extra copy-constructors and destructor calls for referencing an object from a block.

It seems blocks use some combination of stack-storage (i.e. for high-performance downwards funarg) with automatic transition to heap-storage, via __Block_copy() and __Block_release(). The wording of the document ("when the last Block_release occurs") suggests the transition to heap storage may be reference-counted.

Thanks for the ref.

ABI Spec

Just noticed that Apple's Block Implementation Specification is also available.

Previously mentioned on LtU...

Closures for C has been mentioned previously on LtU. (But it's good to bring it up again :-)

It's an interesting idea, although I must say that I'm a bit skeptical. It involves pretty fundamentally changing the C runtime, and it's not clear to me whether that this is a good implementation of closures or not.

Good implementation...

The 'quality' of this implementation of closures seems right up there with the quality of C's integer-types and the inability to easily get the upper half after a full-word integer multiplication or obtain the carry from an add...

C doesn't need a good implementation of closures. It simply needs a quality consistent with the rest of the language, which seems to be achieved by the above design.

The closures themselves don't much affect the runtime library for C. Even the bit of non-conventional implicit memory management can be implemented in terms of the common runtime library. The extra APIs and Grand Central Dispatch to take full advantage of these closures, however...

Apple's documentation

You may be interested in Apple's documentation of blocks:

Blocks programming topics

Regarding some of the comments above:

Captured variables are const snapshots... unless you declare the variable with the __block storage modifier, in which case it's a mutable variable that is shared among all other blocks that capture it. (The variable starts out on the stack, but may be moved to the heap if necessary. This is similar to Lua's implementation of captured variables.)

Regarding "manual memory allocation bugs"... blocks are a C-language feature, but most people will use them within Objective-C. Objective-C's memory management conventions (particularly autorelease pools) mean that most of the time, programmers won't have to worry about manually freeing blocks -- they'll be "use and forget", like any Objective-C object.