Archive for April, 2012

Arbitrary binding pt1 – What is boost::bind and why is it cool?

Posted in C++, Template Metaprogramming on April 22, 2012 by Crazy Eddie

The STL has always been a rather brilliant piece of generic coding. The principles applied created a rather wonderful set of tools that could be used for a variety of conditions without losing type safety and without introducing unnecessary coupling by forcing inheritance. The ability to write generic algorithms that work on any type matching a given concept really adds to the expressiveness and power of C++. Until the advent of boost::bind though, the actual, practical use of these generic algorithms was too painful to bother.

To understand what I mean by this claim, consider the following program that finds all employees that make more than 50k a year:

struct employee
{
    int salary() const;
private:
  // ...
};

// Write special function just to compare salary because binds don't nest:
bool makes_less_than(employee const& e, int amount)
{
    return e.salary() < amount;
}

std::vector<employee> find_all_that_make_50k(std::vector<employee> const& employees)
{
    std::vector<employee> rval;

    std::remove_copy_if(employees.begin(), employees.end(), std::back_inserter(rval), std::bind1st(std::ptr_fun(makes_less_than), 50000));

    return rval;
}

In reality you would either write a functor that does exactly what you need, inheriting from std::unary_function, or you’d just use a for loop because use of all these binds and can get really ugly really fast. Compare the above to the alternative version you can do with boost::bind or with the new std::bind.


std::vector<employee> find_all_that_make_50k(std::vector<employee> const& employees)
{
    std::vector<employee> rval;
 
    // standard version...
    std::remove_copy_if(employees.begin(), employees.end(), back_inserter(rval), bind(less<int>, bind(&employee::salary, _1), 50000));

    // boost version...
    std::remove_copy_if(employees.begin(), employees.end(), back_inserter(rval), bind(&employee::salary, _1) < 50000);

    return rval;
}

This bind construct is even more interesting that this. Say I have an object that will call a function when something happens and I want it to call a method on an object that only takes some of the arguments the other object supplies? In other words, consider what I would do here in this C++03 code:

struct does_something
{
    void set_callback(void (*)(int, double));
};

struct can_respond
{
    void functionA(double);
};

There’s really no reasonable way for me to bind those two things. The best kind of thing one might come up with is to use the observer pattern:

struct does_something_observer
{
    virtual ~does_something_observer() {}
    virtual respond(int, double) = 0;
};

struct does_something
{
    void set_observer(does_something_observer *);
};

struct can_respond : does_something_observer
{
    void function(double);
    void respond(int, double d) { function(d); }
};

This option is suboptimal for three reasons:

  1. It requires we couple can_respond to part of the interface of does_something by inheriting from its observer
  2. We can’t change constness. If we make the callback function const, then subclasses that change in response have to cast it away (dangerous). If we make it non-const then we can’t use const observers.
  3. We force can_respond to implement a signature it’s not interested in, it doesn’t care about the int

Furthermore, most observers have many signatures in them…which is why the Java API has “Adapters” you can inherit from when you only want to listen to one part of the signal interface. Not using this adapter requires that you implement all the functions in the observer interface even if only to make them empty. It’s just a bunch of extra garbage code that fills up the brain (because it has to read it and know why these empty functions are there) without doing anything.

However, when we add an arbitrary function object type like boost::function (which I describe on my old blog — go to “W0t” and follow there) we can get rid of both of these problems:

struct does_something
{
    void set_responder(function<void(int,double)>);
};

struct can_respond
{
    void function(double);
};

does_something ds;
can_respond cr;

ds.set_responder(bind(&can_respond::function, ref(cr), _2));

The great thing here is that we’ve created a 2 argument function object out of a binding that will only use 1 of those arguments to call a function that only accepts one of them. The binder object created by bind can take an arbitrary, implementation defined amount of arguments and they can be anything. Only upon being called (well, when the call has to be compiled) does the system check whether or not the target function can take the arguments supplied, whether they match types, or whether they can be converted and how to do it. Basically, when you assign the binder to the function object by calling set_responder it will attempt to compile operator () with the two arguments that function object’s signature represents. This then will decide what happens.

Using these concepts and adding some loop processing and connection management, the boost::signals and signals2 libraries create a signal/slot mechanism that really surpasses any of the alternatives in its expressive power and in helping keep the coupling to a minimum. Unlike any other event marshaling system, which all require adherence to some specific signature and/or inheritence from a particular object, this system allows you to connect events to any object that can respond to them…ignoring or accepting any information provided by the event source.

THAT is pretty darn cool and brilliantly expressive. It wouldn’t be even half as great without the arbitrary binder. How was this binder created? Stay tuned for the next episode of “Arbitrary Binding”: “How to write your own arbitrary binder”

Advertisements