Hi,
I learned about the blocks feature Apple is implementing as an
extension to C. After looking at it briefly, I concluded it's
basically the same thing as C++(0x) lambdas. But there should be a
difference since if not, (I guess) it would make sense to just adopt
the C++ lambda syntax in C and Obj-C to achieve the goal. So could
someone please point out what blocks provide that C++ lambdas do not
(and vice versa)?
Thanks,
Boris Du�ek
[first answer available at [3]]
[1]: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2009-April/004948.html
[2]: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2009-April/004946.html
[3]: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2009-April/004947.html
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Unlike what has been said in [3], there is a a short syntax with C++0x
lambdas to take every variable in scope by reference. ([&])
The type of a lambda is also unspecified, allowing potentially more
optimal code.
Now, when you look at Apple blocks, it will require __block specifiers
added to variables you want to modify (the very fact that this is
required suggests the whole system is defective).
Variables are taken by reference but then by value when the block
exits the scope (and the copied context necessarily lives on the heap,
it seems). A weird semantic that will only lead to broken designs, but
probably makes people that love GC happy. Without saying this probably
has quite the efficiency cost, of course, since this requires special
indirections.
It is claimed the C++0x lambdas syntax would break compatibility with
C programs, but I don't think that is true. There are probably other
problems to integrate it with C, though, mainly the fact that C can't
really deal with unspecified types and build type erasure.
Apple blocks is really just an ObjC feature they try to generalize to
other languages. For C++, the system designed for that language is
just so much better.
did you mean that if some local variable has __block marker, then it
should not have been declared as local variable in the first place,
and instead should have been declared in some "shared state struct" to
which the blocks would have access (through some pointer)? If yes,
that has been my thought as well.
Here's a link to a "blocks" specification:
http://clang.llvm.org/docs/BlockLanguageSpec.txt
> basically the same thing as C++(0x) lambdas. But there should be a
> difference since if not, (I guess) it would make sense to just adopt
> the C++ lambda syntax in C and Obj-C to achieve the goal. So could
> someone please point out what blocks provide that C++ lambdas do not
> (and vice versa)?
It seems they're similar but the "blocks" feature is more tailored to
C while the C++ lambda feature is more tailored to C++.
The C++ lambda syntax doesn't include a special class of nameable
types that can be used to store or refer to C++ lambda objects. But
you need something like this in order to pass those objects/references
around in C (i.e. call a function with a block as parameter). In C++
you don't need a special class of types for this. Lambda objects are
simply objects of some anonymous type which overrides the function
call operator. If you intent to use this object as parameter to
another function you have a choice between
(1) making the function a template so it can accept the lambda
objects directly (no indirection, inlining possible)
(2) making the function accept a parameter of some function<>
instance (indirection, no inlining possible)
Feature-wise, I think C++ lambdas are more powerful. You can easily
emulate "C blocks" with C++ lambdas wrapped in a polymorphic
function<> object. So, the C++ lambdas are more like a low level
feature whereas "C blocks" are a high level feature which includes
implicit memory and life-time management. To emulate this in C++0x you
could use a shared_ptr which is captured by value and refers to the
"__block" data. So, the following C code with "clang blocks"
// may store block for later use
void bar( int(^blk)(int) );
void foo() {
__block int x;
int factor;
x = 23;
factor = 3;
bar(^(int a){return x += a*factor;});
}
could be translated to this C++0x version
// may store function object for later use
void bar(function<int()> blk);
void foo() {
shared_ptr<int> px (new int);
*px = 23;
int factor = 3;
bar([=](int a){return *px += a*factor;});
}
as far as I can tell. But C++ also allows you to write something like
this:
int foo(vector<int> const& data) {
int accum = 0;
// The lambda object here doesn't outlive this scope
// so it's safe to capture by reference...
for_each(data.begin(),data.end(),[&](int x){accum+=x;});
return accum;
}
which doesn't involve any dynamic memory management w.r.t. the lambda
object and is potentially very fast (inlining of "accum+=x;"). If you
want to support this kind of syntax in C without templates you are
forced to implement this feature with an implicit level of
indirection. Unfortunately, this will remove the possible performance
advantage of lambda objects over function pointers in C++.
Cheers!
SG