On Wed, 02 Sep 2009 08:20:52 PDT Roman V Shaposhnik <[email protected]> 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.