Lambdas and closures have just been voted into C++ 0x. Since this is a blog about beautiful code, I invite you to reflect on the relative beauty of a couple of code examples that were part of the lambda proposal.
Before lambda functions:
class between {
double low, high;
public:
between(double l, double u) : low(l), high(u) {}
bool operator()(const employee& e) {
return e.salary() >= low && e.salary() < high;
}
};
double min_salary;
...
std::find_if(employees.begin(), employees.end(),
between(min_salary, 1.1 * min_salary));
And now with a lambda function:
double min_salary = ....
...
double u_limit = 1.1 * min_salary;
std::find_if(employees.begin(), employees.end(),
[&](const employee& e)
{ return e.salary() >= min_salary && e.salary() < u_limit;});
I suspect I'm not alone in liking the first find_if call better.
Here's the problem. When you use lambda functions, in any language, there is a tension between clutter and expressiveness. And, in fact, the person who wrote that example seems to have been aware of the tension. He introduced an explaining temporary variable u_limit in the lambda version, just to keep the clutter down.
This tension between clutter and expressiveness is unavoidable. The other day, I went back and forth between doing this in Haskell:
signature :: String -> String
signature = filter (\x -> elem x "{;}")
and this:
isSigChar :: Char -> Bool
isSigChar = flip elem "{;}"
signature :: String -> String
signature filter isSigChar
I ended up choosing the first version - the lambda function version. But, Haskell helped me in that choice. It was a win because Haskell's syntax is relatively uncluttered.
Compare this again to the C++ example:
std::find_if(employees.begin(), employees.end(),
[&](const employee& e)
{ return e.salary() >= min_salary && e.salary() < u_limit;});
The lambda in this example has a lot of noise. It has type declarations, and nearly more punctuation than text. The native clutter in C++ shifts the bar in the clutter versus expressiveness tradeoff.
I hope that C++ 0x programmers in exactly this situation will opt for the function object approach, but I suspect that they won't. Function objects are more painful to write. I suspect that, in the end, we'll see gnarlier calls peppering our C++.
Sadly, we've been on the slippery slope for a while already. I understand why, for instance, STL algorithms accept two iterators but it seems odd that there are no versions which enable simple forward iteration over a single container - just pass the container and go. Some teams write little adapter templates, but in most of the industry we have code all over the place which starts like this: find_if(employees.begin(), employees.end(), ...
Calls should be clean.
No, I have no doubt that people will find decent ways to use lambdas in C++, but they are going to have to stretch. This particular example highlights an important issue. The default clutter of a syntax matters. In another language, I'd probably use a lambda but in C++ I prefer this call:
std::find_if(employees.begin(), employees.end(),
between(min_salary, 1.1 * min_salary));
It just reads better.

