C++ Futures: Lambda Functions

Like the Lambada, only different

Intelligent flash storage arrays

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.

Top 5 reasons to deploy VMware with Tegile

More from The Register

next story
Preview redux: Microsoft ships new Windows 10 build with 7,000 changes
Latest bleeding-edge bits borrow Action Center from Windows Phone
Google opens Inbox – email for people too thick to handle email
Print this article out and give it to someone tech-y if you get stuck
Microsoft promises Windows 10 will mean two-factor auth for all
Sneak peek at security features Redmond's baking into new OS
UNIX greybeards threaten Debian fork over systemd plan
'Veteran Unix Admins' fear desktop emphasis is betraying open source
Entity Framework goes 'code first' as Microsoft pulls visual design tool
Visual Studio database diagramming's out the window
Google+ goes TITSUP. But WHO knew? How long? Anyone ... Hello ...
Wobbly Gmail, Contacts, Calendar on the other hand ...
DEATH by PowerPoint: Microsoft warns of 0-day attack hidden in slides
Might put out patch in update, might chuck it out sooner
Ubuntu 14.10 tries pulling a Steve Ballmer on cloudy offerings
Oi, Windows, centOS and openSUSE – behave, we're all friends here
prev story


Choosing cloud Backup services
Demystify how you can address your data protection needs in your small- to medium-sized business and select the best online backup service to meet your needs.
Forging a new future with identity relationship management
Learn about ForgeRock's next generation IRM platform and how it is designed to empower CEOS's and enterprises to engage with consumers.
Security for virtualized datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.
Reg Reader Research: SaaS based Email and Office Productivity Tools
Read this Reg reader report which provides advice and guidance for SMBs towards the use of SaaS based email and Office productivity tools.
Storage capacity and performance optimization at Mizuno USA
Mizuno USA turn to Tegile storage technology to solve both their SAN and backup issues.