Feeds

C++ Futures: Lambda Functions

Like the Lambada, only different

Providing a secure and efficient Helpdesk

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.

Secure remote control for conventional and virtual desktops

More from The Register

next story
'Windows 9' LEAK: Microsoft's playing catchup with Linux
Multiple desktops and live tiles in restored Start button star in new vids
Not appy with your Chromebook? Well now it can run Android apps
Google offers beta of tricky OS-inside-OS tech
New 'Cosmos' browser surfs the net by TXT alone
No data plan? No WiFi? No worries ... except sluggish download speed
Greater dev access to iOS 8 will put us AT RISK from HACKERS
Knocking holes in Apple's walled garden could backfire, says securo-chap
NHS grows a NoSQL backbone and rips out its Oracle Spine
Open source? In the government? Ha ha! What, wait ...?
Google extends app refund window to two hours
You now have 120 minutes to finish that game instead of 15
Intel: Hey, enterprises, drop everything and DO HADOOP
Big Data analytics projected to run on more servers than any other app
prev story

Whitepapers

Secure remote control for conventional and virtual desktops
Balancing user privacy and privileged access, in accordance with compliance frameworks and legislation. Evaluating any potential remote control choice.
Saudi Petroleum chooses Tegile storage solution
A storage solution that addresses company growth and performance for business-critical applications of caseware archive and search along with other key operational systems.
High Performance for All
While HPC is not new, it has traditionally been seen as a specialist area – is it now geared up to meet more mainstream requirements?
Security for virtualized datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.
Providing a secure and efficient Helpdesk
A single remote control platform for user support is be key to providing an efficient helpdesk. Retain full control over the way in which screen and keystroke data is transmitted.