C++ Futures: Lambda Functions

Like the Lambada, only different

Securing Web Applications Made Simple and Scalable

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.

Bridging the IT gap between rising business demands and ageing tools

More from The Register

next story
NO MORE ALL CAPS and other pleasures of Visual Studio 14
Unpicking a packed preview that breaks down ASP.NET
Cheer up, Nokia fans. It can start making mobes again in 18 months
The real winner of the Nokia sale is *drumroll* ... Nokia
Mozilla fixes CRITICAL security holes in Firefox, urges v31 upgrade
Misc memory hazards 'could be exploited' - and guess what, one's a Javascript vuln
Put down that Oracle database patch: It could cost $23,000 per CPU
On-by-default INMEMORY tech a boon for developers ... as long as they can afford it
Google shows off new Chrome OS look
Athena springs full-grown from Chromium project's head
Apple: We'll unleash OS X Yosemite beta on the MASSES on 24 July
Starting today, regular fanbois will be guinea pigs, it tells Reg
HIDDEN packet sniffer spy tech in MILLIONS of iPhones, iPads – expert
Don't panic though – Apple's backdoor is not wide open to all, guru tells us
prev story


Designing a Defense for Mobile Applications
Learn about the various considerations for defending mobile applications - from the application architecture itself to the myriad testing technologies.
Implementing global e-invoicing with guaranteed legal certainty
Explaining the role local tax compliance plays in successful supply chain management and e-business and how leading global brands are addressing this.
Top 8 considerations to enable and simplify mobility
In this whitepaper learn how to successfully add mobile capabilities simply and cost effectively.
Seven Steps to Software Security
Seven practical steps you can begin to take today to secure your applications and prevent the damages a successful cyber-attack can cause.
Boost IT visibility and business value
How building a great service catalog relieves pressure points and demonstrates the value of IT service management.