Bind Vs Lambda?

35,567

Solution 1

As you said, bind and lambdas don't quite exactly aim at the same goal.

For instance, for using and composing STL algorithms, lambdas are clear winners, IMHO.

To illustrate, I remember a really funny answer, here on stack overflow, where someone asked for ideas of hex magic numbers, (like 0xDEADBEEF, 0xCAFEBABE, 0xDEADDEAD etc.) and was told that if he were a real C++ programmer he would simply have download a list of English words and use a simple one-liner of C++ :)

#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

int main()
{
    using namespace boost::lambda;
    std::ifstream ifs("wordsEn.txt");
    std::remove_copy_if(
        std::istream_iterator<std::string>(ifs),
        std::istream_iterator<std::string>(),
        std::ostream_iterator<std::string>(std::cout, "\n"),
        bind(&std::string::size, _1) != 8u
            ||
        bind(
            static_cast<std::string::size_type (std::string::*)(const char*, std::string::size_type) const>(
                &std::string::find_first_not_of
            ),
            _1,
            "abcdef",
            0u
        ) != std::string::npos
    );
}

This snippet, in pure C++98, open the English words file, scan each word and print only those of length 8 with 'a', 'b', 'c', 'd', 'e' or 'f' letters.

Now, turn on C++0X and lambda :

#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>

int main()
{
 std::ifstream ifs("wordsEn.txt");
 std::copy_if(
    std::istream_iterator<std::string>(ifs),
    std::istream_iterator<std::string>(),
    std::ostream_iterator<std::string>(std::cout, "\n"),
    [](const std::string& s)
    {
       return (s.size() == 8 && 
               s.find_first_not_of("abcdef") == std::string::npos);
    }
 );
}

This is still a bit heavy to read (mainly because of the istream_iterator business), but a lot simpler than the bind version :)

Solution 2

C++0x lambdas are monomorphic, while bind can be polymorphic. You cannot have something like

auto f = [](auto a, auto b) { cout << a << ' ' << b; }
f("test", 1.2f);

a and b must have known types. On the other hand, tr1/boost/phoenix/lambda bind allows you to do this:

struct foo
{
  typedef void result_type;

  template < typename A, typename B >
  void operator()(A a, B b)
  {
    cout << a << ' ' << b;
  }
};

auto f = bind(foo(), _1, _2);
f("test", 1.2f); // will print "test 1.2"

Note that the types A and B are not fixed here. Only when f is actually used these two will be deduced.

Solution 3

The C++ 0x lamdba syntax is more readable than the bind syntax. Once you get into more than 2-3 level bind, you code becomes pretty much unreadable and difficult to maintain. I would prefer the more intuitive lambda syntax.

Solution 4

One of the benefits of lambdas is they are way more useful when you need to add a little big of logic on top of an existing function.

With bind, you are forced to create a new function/method/functor even if the logic is only ever needed in this one place. You need to come up with an appropriate name and it can make the code less understandable as it potentially makes you split up related logic.

With lambda, you can add the new logic inside the lambda (but are not forced to if it makes sense to create a new callable).

Solution 5

I think it's more a matter of taste. People that quickly grasp new technologies, or are familiar with functional programming will probably prefer lambda syntax, while more conservative programmers will definitively prefer bind, as it is more in par with the traditional C++ syntax.

Such a decision should be made in coordination with the people that will be working with the code, probably through a majority vote.

Which doesn't change the fact however, that lambda syntax is much more powerful and cleaner.

Share:
35,567
Khaled Alshaya
Author by

Khaled Alshaya

I am member of the team responsible for the design, implementation and maintenance of the financial systems of the largest energy company in the world! If I could allocate some spare time, I spend it mostly on learning new technologies. C++ was the first programming language I learned and I still love using it for personal projects.

Updated on July 15, 2022

Comments

  • Khaled Alshaya
    Khaled Alshaya almost 2 years

    I have a question about which style is preferred: std::bind Vs lambda in C++0x. I know that they serve -somehow- different purposes but lets take an example of intersecting functionality.

    Using lambda:

    uniform_int<> distribution(1, 6);
    mt19937 engine;
    // lambda style
    auto dice = [&]() { return distribution(engine); };
    

    Using bind:

    uniform_int<> distribution(1, 6);
    mt19937 engine;
    // bind style
    auto dice = bind(distribution, engine);
    

    Which one should we prefer? why? assuming more complex situations compared to the mentioned example. i.e. What are the advantages/disadvantages of one over the other?

  • pranavsharma
    pranavsharma over 14 years
    People in a team keep changing. Code readability is very important esp. for future maintenance programmers. Hence we should go with whichever solution that offers more readability and between lamdba and bind, lamda definitely takes the cake.
  • Khaled Alshaya
    Khaled Alshaya over 14 years
    Although the two pieces of code don't do the same thing, I got your point of view very clearly :)
  • KitsuneYMG
    KitsuneYMG over 14 years
    +1. I had to close a vector of FILE* in a dtor. Instead of being able to use a lambda [](FILE* f) { if(f) fclose(f); } I had to create a named function and use that. The function appeared in the private part of the class and was thus separated by many lines from the for_each call
  • Admin
    Admin over 14 years
    the lambda should be: [](const std::string& s) -> bool
  • Khaled Alshaya
    Khaled Alshaya over 14 years
    @Beh Tou Cheh I think the type should be deduced if lambda consists of return <expression>; only(as Thomas did).
  • Alex S
    Alex S about 13 years
    Why not just declare the lambda with explicitly-typed parameters? That would be a vast improvement over the bind solution shown above. Also, if you have more complex functionality that you want to reuse, lambda is still better than bind, since it doesn't require a struct, even if you want to bind state into the functor: template<...>foo(A a, B b, int state){ cout ... << state; } ... auto f = [](const char* a, float b){ foo(a, b, 42); };.
  • MSalters
    MSalters about 13 years
    @Marcelo Cantos: The statement to prove was that "C++0x lambdas are monomorphic", precisely because you must declare the lambda with explicitly-typed parameters.
  • Alex S
    Alex S about 13 years
    @MSalters: The question was (roughly): "Which is better?" I'm not sure how proving that C++0x lambdas are monomorphic answers the question.
  • dv_
    dv_ about 13 years
    @Marcelo Cantos: It shows a difference between the two. AraK asked about differences and benefits/drawbacks of bind vs. lambda.
  • Alex S
    Alex S about 13 years
    Which part of the question is about differences, as opposed to benefits or preference? Even the title uses "vs", which suggests a contest.
  • Thomas Eding
    Thomas Eding over 12 years
    And if you can use the same f with differing argument types, does the compiler give a type error? If so, then both are monomorphic. It's just that lambda has manifest typing, whereas bind uses type inference.
  • dv_
    dv_ over 12 years
    @trinithis: It does not give a type error, since f is a functor with a templated call operator.
  • p12
    p12 over 10 years
    In C++14 even this difference will disappear -- a lambda could be declared as [](auto x){}
  • Fozi
    Fozi almost 10 years
    You don't need a bind here. You can just say auto f = foo();.
  • Andreas Haferburg
    Andreas Haferburg about 9 years
    Disagree. [this](){Type* this_too = this; run([this_too](){this_too->f();});} is neither readable nor intuitive.
  • Drew Dormann
    Drew Dormann almost 8 years
    While this answer wasn't correct at the time it was posted, it is accurate for C++14. The link in the comment above confirms this now.
  • Thomas Eding
    Thomas Eding almost 8 years
    Admittedly I think new lines would help your counterexample. New lines would not help much with bind.
  • c z
    c z almost 3 years
    Personal opinion anyway. Should be a comment, not an answer.
  • c z
    c z almost 3 years
    A member function must be at least 2 pointers because it must store a function pointer, and this, plus at least 1 more value for meta-data such as the number of arguments. The lambda is 1 pointer because it points to this data, not because it's been magicked away.