Lambda expressions in C++

on Feb 11, 09 • by Denis Sidorov • with 5 Comments

Have just stumbled across the lamda module in boost (popular C++ general-purpose library known for extensive usage of templates and influence on C++ standard committee). A quote: The primary motivation for the BLL (Boost Lambda Library) is to provide flexible and convenient means to define unnamed function objects for...

Home » General Coding » Lambda expressions in C++

Have just stumbled across the lamda module in boost (popular C++ general-purpose library known for extensive usage of templates and influence on C++ standard committee).

A quote:

The primary motivation for the BLL (Boost Lambda Library) is to provide flexible and convenient means to define unnamed function objects for STL algorithms …

for_each(a.begin(), a.end(), std::cout << _1 << ' ');

My first thought was: "Hmm ... a macro?" It appears it is not. The <code>_1 object is a lambda placeholder, and should be read as first parameter of lambda expression (a.k.a. unnamed function). In fact the std::cout &lt;&lt; _1 &lt;&lt; ' ' expression is automatically converted into a function-like object, that can be used with most STL algorithms (like for_each, find_if, etc.) So, instead of writing this (a traditional STL way): template <typename T> struct my_printer : public std::unary_function<void, T> {      void operator()(const T &x)      { std::cout << x << ‘ ‘; } }; // … for_each(a.begin(), a.end(), my_printer<my_element_type>());

You can use the above expression, and C++ compiler automatically creates anonymous class that represents an unnamed function. The trick is that all this "behind-the-scene" work is expressed in terms of C++ templates and heavily relies on automatic type inference, and operator overloading. Essentially the module has to overload every possible C++ operator that can be applied to the lambda placeholder, "delay" the evaluation of expression and "wrap" the computation into a callable object.

This approach apparently simulates Lisp lambda expressions (hence the name of the module) and Smalltalk/Ruby code blocks:

Smalltalk

a do: [ :⁣x | Transcript show: x; show: ' ' ]

Ruby

a.each { |x| print x, " " }

Lisp (Scheme)

(for-each (lambda (x) (display x) (display " ")) a)

Lambda expressions and code blocks are essential part of these languages and one of the things that make them consistent and fun to use. Now, this library is trying to adopt this concept into C++.

Pretty cool, but the following limitations lead me to think that this C++ implementation of lambda expressions is far from complete:

  • Boost lambda expressions are not true closures (you can not refer to "non-local" data from the block)
  • Some operators (most notably "." and assignment) can not be overloaded this way, so i = _1 and _1.my_field does not work and requires some extra C++ tricks
  • Can not use statements in this kind of code blocks, works only with expressions
  • If you make a simple mistake in this kind of lambda-expression (or change some related interface), the C++ compiler will gladly present you with a pile of human-unreadable error messages with about a dozen template instantiations with names that do not fit a line of text (no matter how wide your LCD panel is), using each other ... that's a common problem of all non-trivial template libraries

After all, this demonstrates that C++ templates and type inference are indeed powerful concepts, but still not powerful enough to redefine/extend the language in consistent way.

Another problem with this kind of smart C++ tricks is that it creates an illusion of simplicity. As always with C++ - you can not rely on this simplicity, unless you know the details of what's under the hood. If you dare to ignore implementation details you risk losing control over your own code one day.

Related Posts

5 Responses to Lambda expressions in C++

  1. Jerry says:

    The next version of C++ has lambdas built into the language:

    http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions

    I take it this will be much closer to what a lambda is supposed to be. And hopefully without the useless error messages.

    The standard will be approved. But how long will it take people to make compilers that are fully conformant?

  2. Mannings says:

    Good info, thanks! And nice blog!

  3. Symonds says:

    Very Nice blog with a ton of informative information. Can you recommend any decent forums or social groups to join that cover these types of topics. Also, I really appreciate the fact that you approach these topics from a stand point of knowledge and information instead of the typical “I think” mentality that you see so much on the internet these days.

  4. Denis Sidorov says:

    To Olivier: You are right – a lot of other modern languages adopt this concept one way or another. I could have referred to Java closures (http://www.javac.info/closures-v05.html) and Python lambda expressions as well.

    I have included Lisp and Smalltalk because that’s where the original idea of lambda expressions and code blocks was implemented first. And code blocks are important part of Ruby’s flexible syntax – one of the reasons why it has become so popular.

    All these languages used to have this concept as part of original language design – Lisp/Smalltalk/Ruby would be completely different languages if there were no code blocks/lambda expressions.

    In C++/C#/Java lambda expressions are just yet another convenient extension …

  5. You forgot C#:

    
    a.ForEach( x => Console.Write( "{0} ", x ) );
    

    Full program below:

    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace OliIsCool
    {
      public class Program
      {
        public static void Main(string[] args)
        {
          var examples = new List { "C++", "Smalltalk", "Ruby", "Lisp (Scheme)", "C#" };
          examples.ForEach( x => Console.Write( "{0} ", x ) );
        }
      }
    }
    

    …which anybody with the .NET Framework 3.5 can compile as follows:
    c:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe lambda.cs

    Cheers,
    - Oli

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Scroll to top