Skip to content

Binding Data to Functions in C#

July 28, 2011

This is really obvious, but it didn’t even occur to me until I actually needed to do it: binding data to functions in C# is really simple.

When I was building a framework in C++, I used this technique frequently. So before demonstrating how to do it in C# (which seems trivial in retrospect), I’ll describe how it works in C++ and hopefully show why it’s useful.

First, a foray into C++

Let’s say there is a function that does something asynchronously, and when done issues a callback to signify to the caller that the action is complete:

// Prototype for callback function, that sends a reference to a context and a status flag.
// For this example, it doesn't matter what context and status mean, just know that they exist.
typedef boost::function<void(const Context &, Status)> CallbackFunction;
 
// Prototype for a function that does something, accepting a callback as the only argument.
void DoSomethingAsynchronously(const CallbackFunction &callback);

Once DoSomethingAsynchronously completes its thing, it issues the callback to the requester. This is swell, but leaves more to be desired from the user. Let’s say that when it’s done, I’d like additional information to remind my program what it needs to do next. In other words, the function currently provides me with its context, but that’s not the only context I’m interested in: my program has other stuff that it needs available when the callback executes.

In the old (pre-boost::bind) days, this was usually accomplished by passing opaque data as an additional argument to the callback, in the form of a void* pointer:

// Prototype for callback function with an opaque pointer.
typedef boost::function<void(const Context &, Status, void *)> CallbackFunction;
 
// Now the function needs to know what data it should pass back.
void DoSomethingAsynchronously(const CallbackFunction &callback, void *opaqueData);

This void pointer allows holding anything that can be pointed to. Now it’s up to the implementation of DoSomethingAsynchronously to store and return that data during the callback–it doesn’t do anything else with the data (hence the opaqueness).

This works, and is a common way of doing it. However it’s undesirable for two reasons: first is loss of type safety, as there’s no way to know what kind of data arrives at the receiving end, and second is that it creates more work for the asynchronous routine, which now needs to store and return the opaque pointer.

A bind function provides an alternative, type-safe, way. Assume we’re using the original prototypes and not the modified version:

// Here's the callback I want to receive, it gets a pointer to my context in 
// addition to the original arguments.
void MyCallback(boost::shared_ptr<MyWantedContext> myContext, const theirContext &, Status status)
{
    // Do stuff with myContext
}
 
// Here's how I call the asynchronous function so that my context comes back
{
    boost::shared_ptr<MyWantedContext> myContext (new MyWantedContext() );
    ...
    DoSomethingAsynchronously(boost::bind(MyCallback, myContext, _1, _2);
    ...
}

I am a fan of boost::bind function because it provides so much flexibility in composing code that requires function pointers. The _1 and _2 are placeholders that say “include the _nth argument you are actually expecting here when you call my function.” With bind, the arguments may appear in any position, I can drop an argument if I don’t need it (for example if my callback doesn’t want the other Context, remove the _1 and it won’t be passed).

Bind is a template, so type compatibility is checked at compile time. If the signature of the callback doesn’t match what bind sees, it complains (really… when the compiler encounters errors in generic code, it’s not known for being concise in its bellyaching. Expect several screens of errors for a type mismatch).

It’s also nice for library authors, because if their users have access to bind, they need not anticipate every callback requirement of the users; no need for opaque pointers, and the users can knock themselves silly with whatever callback signature they like, and coerce it to match with bind. The library only supplies the simplest API to do its job.

In case you’re curious how it works, the bind function creates an object on the heap to hold the supplied function pointer, and any data bound to it. It returns its own function pointer having the expected signature to DoSomethingAsynchronously. When this function is called, it just chains the call to the supplied pointer with its expected arguments, filling in any bound data and passing through any of the placeholder data. It’s pretty slick and powerful for something so simple.

Now, on to something sharper

Just the other day it struck me that I haven’t needed the bind technique since I’ve used C#, and it made me curious if it was even possible, as I never encountered any bind functions in the .NET libraries.

Then, after some consideration, it dawned on me that that I’ve used bind all along, just under a different name. I’ve been using lambda functions, which are built into the C# language, and make bind unnecessary.

The boost::bind function simulates a couple of features of lambdas: one, creating an anonymous function on the fly (the function pointer returned from it), and two, capturing the variables that are bound to it. A lambda provides more, with its ability to define an entire function instead of just a pass-through.

By limiting the usage of lambda to the same subset of features provided by bind, defining a lambda function that just remaps the callback arguments to the requested signature, the effect is the same:

// This the expected signature of the callback
public delegate void CallbackDelegate(Context context, Status status);
 
// This is the function I want to use as my callback:
public void MyCallback(MyContext myContext, Context theirContext, Status status)
{
   // Do stuff with myContext
}
 
// Here's how the bind is accomplished:
{
    var myContext = new MyContext();
    ...
    DoSomethingAsynchronously((_1,_2) => MyCallback(myContext, _1, _2));
    ...
}

I named the pass-through variables _1 and _2 to make them look like the C++ bind, but they can have any name, so these look a bit funny for most C# coding standards.

The capturing code that the compiler creates for a lambda is very similar to the what boost::bind does, declaring an object on the heap to store the references to the captured objects.

I can take this further, and define the entire callback routine at the place of the lambda declaration, something I cannot do with bind:

// MyCallback not required, just define the function inline
{
    var myContext = new MyContext();
    ...
    DoSomethingAsynchronously((context,status) =>
        {
            // Do stuff with myContext (and context or status)
        }
    );
    ...
}

Of course, if a function is more than a few lines long, it starts to look odd defined inline. For readability purposes, lambdas are best suited to short routines. For long routines the previous delegate approach is easier to read.

In retrospect it seems obvious that bind is a subset of lambda, but that revelation didn’t occur to me until I actually worked it out. I’ll take lambdas when I can, they are much cleaner and more powerful. And most programmers must agree, because they are coming to C++ shortly in the new C++0x spec.

Leave a Reply

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