On Wed, 02 Sep 2009 08:20:52 PDT Roman V Shaposhnik <r...@sun.com>  wrote:
> On Wed, 2009-09-02 at 10:04 +0200, Anant Narayanan wrote:
> > Mac OS 10.6 introduced a new C compiler frontend (clang), which added  
> > support for "blocks" in C [1]. Blocks basically add closures and  
> > anonymous functions to C (and it's derivatives).
> 
> They are NOT closures in my book. They lack lexical scoping. A true
> closure makes the following possible (using JavaScript to stay closer 
> to C syntax):
>    function outer() {
>        var outer_var = 1;
>        return function () {
>           outer_var = { simply: "a different object" }
>        }
>    }

>From reading the URL you cited, it seems you can't return a
block from a function but you can sort of achieve the same
effect by declaring a global `block variable' and assigning a
block to it -- now you can use this block var elsewhere.

int (^ugly)();

int outer() {
    __block int outer_var = 1;
    ugly = ^{ outer_var = 42; }
}

Presumably __block says outer_var is allocated on heap so now
it can live beyond the life of a particular invocation of
outer().  outer_var will have to be freed when ugly is
assigned to a different block. So it seems GC is a
requirement now.  The original C features were "just right"
to keep the compiler simple and still provide a lot of
expressive power. IMHO GC doesn't fit that model.

Because of the heap allocation, most likely you won't get a
proper closure.  For instance, in Scheme

(define (counter)
  (let ((x 0))
       (lambda () (set! x (+ x 1)) x)))

(define c1 (counter))
(c1) => 1
(c1) => 2
(define c2 (counter))
(c2) => 1
(c1) => 3
etc.

Thus on every invocation of the counter function you get a
fresh counter x and c1 and c2 increment their own copy of x
independently. With blocks you'd render the above as
something like:

typedef int(^ctr_t)();

int counter(ctr_t*c) {
        __block int x = 0;
        *c = ^{ return ++x; }
}

ctr_t c1, c2;

void foo()
{
        counter(&c1);   // presumably taking address of a block var is allowed
        printf("%d\n", c1());
        printf("%d\n", c1());
        counter(&c2);
        printf("%d\n", c2());
        printf("%d\n", c1());
}

I bet you'd get 1 2 3 4, and not 1 2 1 3. If they do get this
right, they'd have to allocate a fresh x on every invocation
of counter and this will add to the memory garbage. Now their
GC problem is even worse!  And I haven't even used
concurrency so far!

They very carefully delineate what you can and can not do
with lexically scoped variables etc. but the model is far
more complex.

> > How much effort would it be to support a feature similar to blocks in  
> > 8c (and family)? What are your thoughts on the idea in general?
> 
> Personally I think you'd be better off exploring a connection that a 
> language called Lua has to C. In the immortal words of Casablanca it
> just could be "the begging of a beautiful friendship".

Amen! Or kill one's prejudice against parens (talk to your
parens!) and use Scheme which is about as simple as it can
get.

Reply via email to