The Register® — Biting the hand that feeds IT

Feeds

C++ Futures: Lambda Functions

Like the Lambada, only different

Agentless Backup is Not a Myth

Column The use of “lambda” originates from functional programming and lambda calculus, where a lambda abstraction defines an unnamed function. Lambda functions or Lambdas in C++ are one of the more interesting things to look forward to in the next C++ standard; giving us the ability to treat functions as first class objects at last; composing them inline and treating them as class objects. Up until now we've scraped by with pointers to functions, and various libraries like Boost Lambda, both of which approaches suck.

The syntax for declaring function pointers can get so cryptic that at a large percentage of C++ interviews, it's used to filter out the weak applicants. Boost et al. do a good job given the limits of the language; but again if you try anything more ambitious than a simple predicate then debugging can get very painful. They offer, as Valentin Samko says with heavy irony in his proposal here, the opportunity to learn "numerous highly non-trivial programming techniques".

All by themselves they beat the amateur efforts in the International Obfuscated C contest. However, it would be nice to be able to write something like this (where the code is passed just as if were any other type of variable):

 void KillByVal(const int x , std::vector<int> & Vec) {
 std::remove_if(v.begin(), v.end(), bool (int& n) { n == x; }
 };

The first thing to notice is that the predicate we supply can see the parameter x directly. Lambdas will naturally have the scope of the enclosing function, and since they aren't full classes will include the local this pointer without clashing. This style of coding is giving a big hint to the compiler for inline optimisations.

Before I get letters of complaint, yes I know you can do some of this with #define, but if you know how to do this, you also know why it's such a tragically bad idea.

Loopless code

Explicit loops are not just sources of the "out by one" family of bugs, but also are often less efficient than the STL algorithms, a fact that is, surprisingly, still unknown to a good percentage of programmers.

I adhere to the notion that the closer the mapping between intent and implementation, the better the code. You may not agree; if so, that's presumably why you're still using MFC. However, to many people it is more intuitive to "apply" code to a set of data, saying in effect "do this action to it", rather than to explicitly iterate though each value. This is not only because it feels more elegant, but also because if you don't specify a deterministic sequence, a smart compiler with access to multiple CPU cores or hardware assist (as in GPUs, PPU or SIMD architectures) can generate much better code. Even my laptop now has twin cores (if yours doesn't, I win) – and by the time this stuff hits your compiler, multiple CPUs will be very common. STL already makes use of function objects for a variety of For_Each replacements for the classic C style loop.

Another way in which functors and function pointers are weak is in not meshing with the scope of the code you're writing. Since they are in a separate context, they simply cannot know about variables local to their invocation unless you're dumb enough to use globals to communicate with them.

Lambdas will enjoy access just as if they were a block within the scope of a function body; and that includes access to this when it's a class member; but since a lambda isn't quite a class it has no this pointer to clash with it.

Nevertheless, being an object, a Lambda's lifetime isn't bounded to the function in which it is created, and so, even before compilers support this feature, we have a new variant on an old type of bug. Just like pointers to local objects, Lambdas may reference variables and continue to do so after it is no longer safe; and, before you ask, even the smartest compiler can't catch all cases. There is now a serious debate on how variables get into the Lambda: should they be copied or referenced? References are more dangerous, but, in many cases, vastly more efficient than copies for larger objects; but the copies are vastly easier to multi thread.

Lambdas will be declared with much the same syntax as you'd expect for a function, taking forms like:

 Return_Type Name (Type1 P1,.TypeN PN);
<> (Type1 P1, Type2 P2, ...)

For example:

<> (auto x, auto& y) { y += x; } is equivalent to template<class T1, class T2> void (T1 x, T2& y) { y += x; }

And a return type is only necessary if it cannot be deduced (normally, it's prefixed by ->). This means that the compiler can immediately recognise that it’s not an older style function, which should make error messages more comprehensible.

We currently use function names to reference the address of piece of code when creating thread procs or callbacks, again making encapsulation more clunky. Most O/S level thread and callback APIs don't really handle the passing of parameters to their functions well, mostly because of irritating stack issues; and also because, in their heart of hearts, both Windows and UNIX are really still C APIs.

As a side effect of this, Lambda objects also refer to a specific context of execution; so two Lambda objects created by the same or identical code may refer to two different contexts of execution, and therefore different sets of local variables:

 APICreateThread ( tr1::function<void(int)>)

 CFeed::FireThread (int ct)
 {
 APICreateThread (void(int i) : (Repeat (ct)) { for (int i=0; i!=ct; ++)
 DoStuff(); });
 }

Old function pointers may point anywhere, with zero often being used to mean “uninitialised” — and of course that means every so often you end up jumping to zero and dying horribly. Lambdas, on the other hand, are more like references than pointers in that they must point to some block of code; and not being pointers stops people coding atrocities like address arithmetic before calls.

You cannot do address arithmetic on function pointers unless you reinterpret_cast them, but then you get what you deserve.

Lambdas look likely to be in C++Ox, but work is still under way, and the committee is planning to review refined versions relatively soon. And, just to refer back to my provious C++ divided by CLI article, the committee has rejected Microsoft’s proposal. I really can’t decide whether that’s good or bad, so I'll just end here, I think.

Regcast training : Hyper-V 3.0, VM high availability and disaster recovery

Latest Comments

Boost Phoenix?

Have you seen Boost.Spirit's Phonix lambda interface?

http://spirit.sourceforge.net/distrib/spirit_1_7_0/libs/spirit/phoenix/index.html

That enables you to do pretty much what you want to do with the futures or lambda given the current C++ implementation.

0
0
Anonymous Coward

You're not hired

Your first example:

void KillByVal(const int x , std::vector<int> & Vec) {

std::remove_if(v.begin(), v.end(), bool (int& n) { n == x; }

};

The remove_if is missing the closing ')'.

Function definitions should not have a ';' after the closing '}'.

0
0

Unreadable syntax

While lambdas are undoubtably a boon to C++ (or any other language that don't already have them), I find the syntax to be unreadable. This may be because I find C++ syntax in general to be horrible, but for comparison you should look at languages like Haskell or SML. I'm not saying that the syntax of these langauges can not be improved, but they are a damn sight more readable than C++ -- lambdas or no lambdas.

0
0

More from The Register

SCO vs. IBM battle resumes over ownership of Unix
Zombie lawsuit back and wants to suck the brains out of Linux
Bjarne Again: Hallelujah for C++
Plus: Now officially OK to admit you never used STL algorithms
Interwebs taunt Sir Jony over Apple eye candy makeover
Hey Ive, Ive... add more unicorns, willya?
Apple: iOS7 dayglo Barbie makeover is UNFINISHED - report
Plus: You don't like the icons? Blame marketing
Red Hat to ditch MySQL for MariaDB in RHEL 7
So long, Oracle! Don't let the door hit you on the way out
Shy? Socially inadequate? Fiddling with your phone could help
App 'tells the brutal truth' about social inadequates' chatup lines
Java EE 7 melds HTML5 with enterprise apps
New release arrives with GlassFish, NetBeans support
 breaking news
'Office Facebook' firm Tibbr wants you to PAY for mobe-meetings app
Great idea. Punters won't cough for it though
 breaking news
The only Waze is Google: Ad giant tipped to gobble map app 'for $1.3bn'
Pac-Man-satnav-ish upstart in bidding war with Apple, Facebook
 breaking news
PM Cameron calls for modern, programmable computers! (We think)
IT education musings to G8 chiefs to mystify IT industry