Generic Lambdas

GenericLambdasWhen C++11 came to a compiler near me, one of the first features I was eager to try was lambdas.  As a fan of highly-structured code, I had often factored out “local functions” in my designs.  Because nested functions are prohibited in C++ (why?), I’d often rely on the technique of declaring a nested struct with a public static (stateless) method.  This achieves the same effect as a local function with a minimum of fuss.  Some libraries (e.g., Boost) provide macros to fabricate local functions, hiding the “ugliness.”  But it’s not that bad, and the struct name can be useful in providing some self-documenting organization.  Also, I tend to prefer keeping non-language subterfuge to a minimum.  It creates a clutter all its own.  But I digress – I was talking about lambdas.

I’ve used lambdas in C# since their inception as part of LINQ (a technological tour de force, by the way).  They permit a “locality of reference” for the programmer, permitting anonymous function object arguments to be implemented at the point of their use.  This reduces both a great deal of boilerplate code, and cognitive load on the programmer.

A Degrading Experience

So, when lambdas debuted in Visual C++, I eagerly put them to the first use I could find, and was… disappointed.  I had in mind to replace some of my nested struct method uses with lambdas, specifically for calling Windows APIs that accept a C callback function.  My scenario was thus aimed squarely at the “captureless lambda degrades to a function pointer” feature of lambdas. I can smile about it now, since this behavior is now available in Visual Studio 2012 .  I mean, how cool is this?

EnumWindows([](HWND, LPARAM){return TRUE;}, 0L);

I’ve since used lambdas in countless contexts and still regard this as my favorite C++11 feature (second only to “auto“).  However, it wasn’t long until I discovered several more basic limitations of lambdas.  Another was lack of support for contravariance.  Now, I understand that C/C++ has never had this, so maybe just seeing it again in the new lambda light has made me wistful.  But I’d really like to be able to do this:

struct ParamBase{};

struct ParamSub : ParamBase{};

void Bar( void(ParamSub & p) );

void CallBar()
	Bar([](ParamBase & p)
		// I only care about ParamBase in my lambda,
		// so why can't I use contravariance?

Deduction for the Win

Most of the limitations I’ve encountered, however, could be summarized as a lack of generic (polymorphic) support.  In short, there are many situations in which type deduction would make lambdas more compact and readable.  I’m excited that this is getting some attention.  After co-authoring a proposal, Faisal Vali has created a test implementation and made it available here.  I ran across this on the official C++ website, which is calling for comment on Faisal’s work.  As should be expected, the approach is thorough and thoughtful, and I’ll have a hard time waiting for the standards committee to do their thing.  Still, assuming the proposal is adopted essentially without change, C++ haters are gonna have a field day with this syntax:


And it won’t be the Lispers.  They’ll love all those delimiters, bringing C++ asymptotically closer to FP enlightenment.  But pray, what will we do when we need the next pair?