Closures In Straight C

I’ve read a lot lately about closures. I’ve read articles where people wonder what they are, others where someone is lamenting the fact that they only recently discovered them. I too only recently discovered the joy of closures. I’ve been writing a lot of javascript recently and I love the way writing anonymous callback functions works. But it turns out I have already been using closures for a long, long time.

A friend and I were discussing C (our language of choice for embedded programming) and the things we like about it and somehow the subject of closures came up. I started thinking about what it would take to implement closures in C. Would you do it in the compiler as a language extension or just build them up by hand using in C itself in a cross-platform way?

And then it struck me: I’ve already been using, in straight, boring old C, the concept of closures. And I’ve been using them practically forever. I would say almost since I first learned C on my Macintosh back in high school.

The original Mac API (which still mostly lives on in Mac OS X’s “carbon” API) has an element in almost every major structure called “refCon”. The Apple documentation sorted of glazed over them (or maybe I glazed over when reading about them) and so I puzzled over these for a long time until I realized that they were pieces of memory that the Mac system would never look at or change. They are for the application writer to use as they see fit.

Apple also uses them when you register a function that the system will call at some later time. Here’s an example I grabbed from the current carbon window manager documentation:

OSStatus InstallWindowContentPaintProc(WindowRef window,
                                       WindowPaintUPP paintProc,
                                       WindowPaintProcOptions options,
                                       void *refCon); 

What might you use one for? Well typically you’d create a structure with whatever local data needs to be associated with the call back function and put the pointer to that structure into the refCon. The callback function (since you’re writing it) knows to cast the refCon to the appropriate structure pointer so that it can get access to the fields of the structure.

This is by no means some great thing that Apple discovered. Almost every C API that has callbacks uses the same sort of concept. Here’s a function prototype from glib (one of the gnome base libraries):

guint g_io_add_watch(GIOChannel *channel,
                     GIOCondition condition,
                     GIOFunc func,
                     gpointer user_data);

Here “user_data” serves the same purpose as “refCon” did in the first example. The function you pass in “func” will get “user_data” passed to it (unmolested) by glib.

I’ve used this in almost every API I’ve ever written that has callbacks. Here’s another example from an embedded project I’m working on:

void add_timer(int (*timer)(), void *cookie, int timeout_ms); 

I always name my refCons “cookie”, for some reason. Arguably “user_data” is a more descriptive name, but I sort of like the arbitrariness of “cookie”. Or maybe it just makes me think of cookies… MMMM… Cooookies…

So when I learned javascript and started coding Green Felt I wrote a little XMLHttp() wrapper to make the interface nicer (like every other ajax developer on the planet) and I put in a cookie. Later I realized that everything I was passing in the cookie was a local variable and therefore was already saved in the closure. So passing it explicitly through my ajax function was pointless.

It turns out that all those “cookie”, “user_data”, and “refCon” pointers that I had been using since I first learned C transform the user supplied function pointers into “closures”. They do it explicitly and without any syntactic sugar, but they are 100% the same conceptually. In effect you allocate some memory, put references to some of your local variables into the structure and then pass the structure along with the function pointer to be called back later. The callback can use the structure all it wants which ends up being equivalent to a real closure having direct access to those same local variables.

So… Closures aren’t anything new. C has had closures forever. Yes, you have to manually allocate and deallocate the memory for your variables without syntactic sugar… But, hey, that’s C!

13 thoughts on “Closures In Straight C”

  1. This isn’t really closure – you have to manually create the environment you want to capture (your struct) and make it have dynamic extent(stuff it at file scope or malloc it).

    Extremly painful compared to languages with real closures.

  2. But you see, that is my point. The “closing over itself” is just syntactic sugar.

    C only supports 2 types of variables. Global variables and stack based local variables. Anything more than that is supported by the standard library—malloc, to be specific.

    The point is that you have to hand hold C to get anything that lasts longer than a local stack variable but shorter than a global variable (which lasts forever).

    By passing these user data pointers around with the function pointer itself, you are effectively passing around your local lexical environment—just the parts you care about.

    Like you guys pointed out (and as I said in the article), it’s painful to do compared to a language with language level closures.

    But that’s the way it is with C for practically everything! It’s the exact same concept as a closure, regardless of how much extra you have to do to implement it…

  3. The difference is the same as between “I want X, Y and Z” and “I want everything”.

    If you only want X, Y and Z in the first place, that’s going to be fine, it will work in that limited case. But I don’t know how you’d express “everything” in C.

    What you want is a pointer to the current scope, not a pointer to a copy of some of the variables from the current scope.

    Douglas

  4. Douglas, I’m not sure what you mean by “everything”. Please explain.

    You could keep a pointer to you local variables (if you were sure the callback were going to happen before they go away) or you could use the variables in the created structure instead of locals (this is what C folk tend to do in these cases).

  5. As a long time C developer, I totally agree that callbacks and cookies are the closest thing to closures in the C world. Of course, we all know it’s not part of the language, so it’s not as intuitive and natural to use. However, I think the point of the article is that C developers can and have been able to “simulate” the behavior.

  6. I actually found this article very useful. I have been working in Node.js lately and realized that it’s asynchronous approach could actually simplify some error handling aspects in C. The only problem: closures. However, following your lead, as long as every function has a “context” object, you can overcome that limitation. Sure, the developer has to allocate/deallocate memory, but I don’t think this is “inconvenient”. Simply define a “context” object for each function, allocate that context for each “instance” of that function and pass it and the context as a callback. I may look into creating an async library in C, similar to caolan/async, just to play around with the concept.

  7. Thanks, I too have found this useful in embedded environment. Beats having global or static global variables. As others have pointed out, it may be quite far from closures as they are traditionally understood, but I wouldn’t have found this article by googling “closures in C” if you didn’t mention them. Ended up having code similar to this:

    typedef struct
    {
    int counter;
    } context_t;

    static void onEventCallback(void *event, void *context)
    {
    context_t *self = (context_t *)context;
    self->counter++;
    }

    void processAsync()
    {
    context_t context, *self = &context;
    self->counter = 0;
    startProcess(onEventCallback, self);
    }

  8. I remember having a hard time understanding what magic tricks were going on with closures, which vanished when I figured out the equivalency you mention.
    Of course it is easier with language support but the point is that it is functionally equivalent..

  9. I quite agree with Travis Parks and Anonymous; this was a useful insight. Especially in an embedded environment where you must use C, having the ability to simulate closures (with a bit of manual paperwork) is very useful.

    You can simulate many of the features of modern OO languages in C (or even assembly!); it just puts the entire responsibility for enforcing discipline on the programmer. OO languages provide the “syntactic sugar” (easy syntax) and enforcement of visibility and access. For example, pointers (usually to structs) simulate objects: a single opaque value represents the object. As long as you don’t break the opacity (your responsibility in C, but enforced by the language in C++/java/etc.) you’re good. Examples of this include the X11 libraries (and other windowing libs of the time). C++ closures must allocate variables from the heap (vs. stack for auto locals), an issue for embedded systems. Just as in Cfront (the original C++ compiler, which compiled C++ to C), Class name, method signature (number and type of arguments), and method name can be encoded in the function name (“name mangling”) (implementing function overloading), and calling virtual methods in C can be simply translated to a dereference of a function pointer in your object’s struct. Thus C coding standards (adhered to with discipline) can be used to simulate these OO features. Admittedly, this is making the programmer do the work the OO compiler would do automatically. An interesting intermediate approach can be found in Perl, which has object-oriented syntactic sugar, but exposes the underlying implementation, permitting breaking opacity. Many languages, like JavaScript, have this intermediate approach.

    I don’t think we’re claiming that C is an object-oriented language; it was never designed to be one. We’re trying to find ways to bring more tools into our toolbox, to bring to bear when we need to solve problems in C (a constraint of many embedded systems).

Leave a Reply

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