[cfe-dev] "Blocks" in Clang (aka closures)

David Chisnall csdavec at swansea.ac.uk
Tue Sep 2 08:27:00 PDT 2008


Hi Chris,

A couple of questions about this:

1) In Seaside (Smalltalk web-app framework) blocks are used as a way  
of implementing continuation passing.  This requires support for re- 
binding variables in the closure.  Smalltalk does this via the  
BlockContext object.  Is there an equivalent of it here?

2) I know of two existing implementations of blocks in Objective-C,  
one by Brad Cox in 1991 and one by David Stes in 1998.  Both used  
similar syntax (David Stes simply made untyped arguments default to  
id).  What was the rationale for designing a new syntax for block  
literals?  Was this to allow Objective-C syntax blocks which are  
objects encapsulating C blocks?

3) Why is the __block storage class required as an explicit type  
tag?  Can this not be inferred by the compiler (i.e. any variable you  
assign to in the block is promoted, others are copied)?

3a) It isn't clear from your example what happens if I create a block  
referencing a (non-__block) variable, assign it to a global variable  
(or an instance variable in another object somewhere), modify the  
referenced variable on the stack, and then invoke the block  
function.  Does the block see the old or the new value?  If it's the  
old value, then I think this answers my previous question but sounds  
like it will confuse programmers.  It seems that it would be less  
confusing if every block-reference variable implicitly received the  
__block storage class, and an explicit tag was made available for  
variables which should be bound-by-copy.

Exciting news, anyway.  I look forward to being able to replace my  
Objective-C BlockClosure class used in Smalltalk with something  
better supported.  Being able to pass blocks to Objective-C code from  
Smalltalk has reduced code complexity in a lot of cases for us, and  
being able to do the same thing (and the converse) from Objective-C  
is likely to make a lot of people very happy.

David

On 28 Aug 2008, at 04:00, Chris Lattner wrote:

> Hi All,
>
> Steve has started working on an implementation of a language feature
> named 'Blocks'.  The back story on this was that it was prototyped in
> an private Clang fork (because it is much easier to experiment with
> clang than with GCC), then implemented in GCC (where it evolved a
> lot), and now we're re-implementing it in Clang.  The language feature
> is already supported by mainline llvm-gcc, but we don't have up-to-
> date documentation for it.  When that documentation is updated, it
> will definitely be checked into the main clang repo (in clang/docs).
> Note that llvm-gcc supports a bunch of deprecated syntax from the
> evolution of Blocks, but we don't plan to support that old stuff in
> Clang.
>
> Until there is more real documentation, this is a basic idea of
> Blocks: it is closures for C.  It lets you pass around units of
> computation that can be executed later.  For example:
>
> void call_a_block(void (^blockptr)(int)) {
>    blockptr(4);
> }
>
> void test() {
>    int X = ...
>    call_a_block(^(int y){ print(X+y); });  // references stack var
> snapshot
>
>    call_a_block(^(int y){ print(y*y); });
> }
>
> In this example, when the first block is formed, it snapshots the
> value of X into the block and builds a small structure on the stack.
> Passing the block pointer down to call_a_block passes a pointer to
> this stack object.  Invoking a block (with function call syntax) loads
> the relevant info out of the struct and calls it.  call_a_block can
> obviously be passed different blocks as long as they have the same  
> type.
>
>  From a technical perspective, blocks fit into C in a couple places:
> 1) a new declaration type (the caret) which work very much like a
> magic kind of pointer that can only point to function types. 2) block
> literals, which capture the computation  3) a new storage class
> __block 4) a really tiny runtime library.
>
> The new storage class comes into play when you want to get mutable
> access to variables on the stack.  Basically you can mark an  
> otherwise-
> auto variable with __block (which is currently a macro that expands to
> an attribute), for example:
>
>
> void test() {
>    int X = ...
>    __block int Y = ...
>    ^{ X = 4; };  // error, can't modify a const snapshot.
>    ^{ Y = 4; };  // ok!
> }
>
>  From the implementation standpoint, roughly the address of a __block
> object is captured by the block instead of its value.
>
> The is tricky though because blocks are on the stack, and you may want
> to refer to some computation (and its __block captured variables)
> after the function returns.  To do this, we have a simple form of
> reference counting to manage the lifetimes of these.  For example, in
> this case:
>
> void (^P)(int);  // global var
>
> void gets_a_block(void (^blockptr)(int)) {
>    P = blockptr;
> }
>
> void called_sometime_later() {
>    P(4);
> }
>
> if gets_a_block is called with a block on the stack, and
> called_sometime_later is called after that stack frame is popped,
> badness happens (yay for C!).  Instead, we use:
>
> void (^P)(int);  // global var
>
> void gets_a_block(void (^blockptr)(int)) {
>    P = _Block_copy(blockptr);  // copies to heap if on the stack with
> refcount +1, otherwise increments refcount.
> }
>
> void called_sometime_later() {
>    P(4);
>    _Block_release(P);  // decrements refcount.
>    P = 0;
> }
>
> The semantics of this is that it copies the block off the stack *as
> well as any __block variables it references*, and the shared __block
> variables are themselves freed when all referencing blocks go away.
> The really tiny runtime library implements things like _Block_copy and
> friends.
>
> Other interesting things are that the blocks themselves do limited/
> optional type inference of the result type:
>
>    foo(^int(){ return 4; });   // takes nothing, returns int.
>    foo(^(){ return 4; });      // same thing, inferred to return int.
>
>
> If you're interested in some more low-level details, it looks like  
> gcc/
> testsuite/gcc.apple/block-blocks-test-8.c in the llvm-gcc testsuite
> has some of the underlying layout info, though I have no idea if it is
> up-to-date.
>
> To head off the obvious question: this syntax and implementation has
> nothing to do with C++ lambdas.  Blocks are designed to work well with
> C and Objective-C, and unfortunately C++ lambdas really require a
> language with templates to be very useful.  The syntax of blocks  
> and C+
> + lambdas are completely different, so we expect to eventually support
> both in the same compiler.
>
> In any case, more detailed documentation will be forthcoming, but I
> would be happy to answer specific questions (before Friday, at which
> point I disappear for two weeks on vacation, woo!)
>
> -Chris
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev




More information about the cfe-dev mailing list