Why Lambda will Change C++
Of all the new features coming into C++'s next version of the language standard, I think definitely one of the things which will make the single biggest change will be the addition of support for lambda. Before I go into that, let me give some context into why I've gone into thinking about this a little, and why I've chosen to blog about it.
It's a long weekend here in the Philippines and I thought to myself (in between learning Python and polishing my C++ skills) I should take a look at functional programming and immerse myself in the feel of thinking more in terms of functions. So I picked up a college textbook I used to read a lot and turned the pages towards functional programming languages. The first pure functional programming language that I've been able to learn and use to some extent is LISP.
So I tried to be ambitious and use the HTTP client that was available as an open source library. I quickly found out that I don't have enough LISP voodoo to pull that off so I said let me get back to the basics first.
After (re)learning how to use 'mapcar' and revisiting my recursive programming archives, I got back into the groove.
However, one thing I noticed is that working in a functional programming language's environment and context changed the way I looked at problem solving: instead of working at the level of types and classes and design, I was looking at functional solutions -- contexts, function applications. I wasn't thinking about concurrency, storage, efficiency -- what mattered to me was that when I implemented a factorial function, it would be alright to get the factorial of 100 and not worry about efficiency.
It was changing the way I approached problem solving by going at a higher level than I was used to in my day-to-day programming. This allowed me to think of the problem at an abstract level and solve it in that level instead of worrying about the lower level details -- like memory allocation, locality, and concurrency concerns.
Then reality kicks in, and I realize that the problems I'm solving are nowhere near the domain of 'abstract computation'. Although admittedly, the higher level problems I face I would rather solve in a higher level language like LISP/Scheme/Haskell -- but crossing that language barrier means more moving parts and more problems in the long run.
So back to the context of the post: if there was a way to be able to construct C++ programs in a functional manner -- or support functional programming more closely in the language -- then somehow I might just be able to approach the higher level problems I've been tackling in a more familiar language, and also in a familiar way of computing. Thinking in terms of functions instead of strictly types and the interaction between "objects" would greatly abstract the problems and therefore the solutions being created.
One thing that surprised me with my experiments with LISP recently is the ease of defining 'nameless functions'. Of course in C++ there are libraries that allows you to do these -- Boost.Lambda, Boost.Bind, and Phoenix (part of the Boost.Spirit parser framework). The STL algorithms in C++ also allowed you to think in functional programming terms, using terms like 'transform', 'for_each', among others. But there was something missing.
In LISP, you were able to do (mapcar lambda(x) (* x x) '(1 2 3)) and get a list (1 4 9). In C++, unless you used one of the earlier mentioned libraries, you'd have to write your own simple functor which returned the square of a number. In C++, you'd have to worry about types -- for example, would you return a long when you took in an int to account for the possibility of overflow, or a double, or a special type of integer. To be fair about it, I'm not exactly comparing apples to apples. But the point of it is that the above one-liner was practically impossible to turn into a one-liner in C++... until C++0x where you were able to do lambda's.
The promise of lambda support (and new style iterator support) in C++ is the ability to do transform(container, [](auto x)->decltype(x) {return x * x;}, back_inserter(result_container)) -- which transformed each element of container by applying the lambda function [](x)->decltype(x) {return x*x;} and then storing the result into the 'result_container'.
This then allows C++ programmers to think in functional programming terms and think about how functions will be applied to data instead of how to create loops that performed operations in a sequential manner. Consequently, this allows for simple(r) parallelization of programs by the compiler or by supporting facilities (libraries, frameworks, etc.). For example, compilers in the future can choose to determine if the lambda expression are re-entrant and can be parallelized automatically (Intel compilers are already leveraging the Streamed SIMD Extensions in their compilers). Even better would be the use of parallel-aware containers and STL implementations which automatically distribute load among worker threads under the hood (transform might do runtime analysis on the size of the container and automatically map the computations to processing threads and then collect the information in a final collection step).
The possibilities that lambda opens up for C++ are endless -- consider for example being able to expressively and consisely define operations on data to be performed on multiple machines. One day perhaps the functional programming roots of the Google MapReduce system would take on a whole new level -- with open source frameworks in C++ which allowed programmers to define bite-sized chunks of C++ to be the mappers and reducers. One interesting thought is the possibility of packaging these lambda expressions into network-streamable nuggets self-contained to be executed and distributed even on global scale computers (think SETI@home and global scale utility computing).
All this and more can be made possible just by adding better support for functional programming in C++. Couple this with the very powerful object oriented programming support, generic programming support of C++, and efficient very high performance machine code, and you've got yourself a language fit to handle the programming/engineering problems of the future. Suddenly, C++ turns into a must-learn language to be able to leverage the shift from sequential computing and object oriented programming towards parallel computing and functional programming. If there's ever a good time to be learning/using C++, now is definitely the time.
Definitely exciting times ahead.



6 comments:
I agree with you, c++0x will be a major boost ;) to c++.
When I saw that lambda expressions are a part of c++0x I only thought of them as syntactic sugar. But you make a great point here. This "little" extra we might get from lambda expressions sounds similar to intel's TBB, but being standardized gives it a lot more support (compiler support, user base, ...) in the long run.
Exciting times indeed.
Good introduction to Functional programming is lecture notes by John Harrison
And yes, introduction of functional parts into C++ (lambda, function, fusion, etc) make this language more usable
No, no, no, no, no! That's truly nasty and evil. I fully understand why one would want lambda, since functors are a righteous pain. However, adding lambda is starting down the path toward making C++ something completely different -- and potentially something that ultimately isn't C++. Besides, the syntax used is completely hideous.
For a good example of a feature that may end up redefining the language is the new push to add closures to Java.
Greenspun's 10th Rule of Programming: Inside every sophisticated program or system lies a badly written and buggy Lisp Interpreter.
great post, although I must admit I didn't understand it all, from the sounds of things though I think this will reduce the number of lines of code needed to express some thought (from being explicit to more implicit) ... and still allow you to have complete control my modifying lambda functions.
Just a note: Lisp is not a purely functional language; it is multi-paradigm. It supports and encourages the functional style, but it also allows you to create side-effects, as in imperative programming.
Lambda is exciting, and will be very useful.
Having said that, C++ will never be a functional programming language, but that's okay-- we're used to multiple paradigms. Hopefully, lambda functions will be well supported.
They're great for "trivial" functions, but hopefully folks won't loose sight of the appropriateness of function objects (a C++ way to express a closure) for anything that's non-trivial.
C++ continues to improve, and continues to be an amazingly expressive and well-supported programming language.
Post a Comment