I recently discovered something that's very old news to functional programming people, but was new to me, especially as being applied to C. It is common practice in C coding to use callback functions when a general routine needs to do something specific that the caller knows about. Furthermore, a void* cookie is generally used to pass context to this callback.

Here's a simple C99 example of a linked-list structure and a iterator that calls a callback function for each element of the list. The iterator takes a cookie argument, which it passes on untouched to the callback. This cookie means something to the caller of the iterator and to the callback, but it means nothing to the iterator itself. This is the usual idiom. Furthermore, the example contains a simple use of this iterator, to print all node values to a particular FILE:

#include <stdio.h>

struct node
{
    int x;
    struct node* next;
};

typedef void (*foreach_callback)(const struct node* node, void* cookie);

static void foreach(const struct node* list,
                    const foreach_callback cb, void* cookie)
{
    while(list != NULL)
    {
        cb(list, cookie);
        list = list->next;
    }
}




static void print_node(const struct node* node, FILE* fp)
{
    fprintf(fp, "%d\n", node->x);
}

static void print_nodes(const struct node* list, FILE* fp)
{
    foreach(list, (foreach_callback)print_node, fp);
}

int main(void)
{
    struct node list =
        {.x = 10,
         .next = &(struct node){.x = 11,
                                .next = &(struct node){.x = 12,
                                                       .next = NULL}}};

    print_nodes(&list, stdout);
    return 0;
}

This works fine, and things have been done this way for a very long time. As written, print_node() is visible to most of the source file, even though it is only used by print_nodes(). It would be nice if print_node() was visible only from that one function that uses it. This is not possible in standard C. However GCC has a non-standard extension that allows such things: nested functions. With that in mind, we can rewrite the example like so:

#include <stdio.h>

struct node
{
    int x;
    struct node* next;
};

typedef void (*foreach_callback)(const struct node* node, void* cookie);

static void foreach(const struct node* list,
                    const foreach_callback cb, void* cookie)
{
    while(list != NULL)
    {
        cb(list, cookie);
        list = list->next;
    }
}




static void print_nodes(const struct node* list, FILE* fp)
{
    void print_node(const struct node* node, FILE* fp)
    {
        fprintf(fp, "%d\n", node->x);
    }


    foreach(list, (foreach_callback)print_node, fp);
}

int main(void)
{
    struct node list =
        {.x = 10,
         .next = &(struct node){.x = 11,
                                .next = &(struct node){.x = 12,
                                                       .next = NULL}}};

    print_nodes(&list, stdout);
    return 0;
}

That's nicer. print_nodes() is now self-contained, and none of its implementation details leak out. At this point we're not using the nested function as anything more than just syntactic sugar. However, these aren't simply nested functions; they're full closures, i.e. the nested function has access to the local variables of its surrounding scope. This means that print_node() can see the fp argument to print_nodes(), and doesn't need to be passed it. Thus we do not need the cookie! The state maintained by the nested function takes on the work that the cookie did for us previously. As such, we can rewrite this example with no cookies at all:

#include <stdio.h>

struct node
{
    int x;
    struct node* next;
};

typedef void (*foreach_callback)(const struct node* node);

static void foreach(const struct node* list, const foreach_callback cb)
{
    while(list != NULL)
    {
        cb(list);
        list = list->next;
    }
}




static void print_nodes(const struct node* list, FILE* fp)
{
    void print_node(const struct node* node)
    {
        fprintf(fp, "%d\n", node->x);
    }


    foreach(list, print_node);
}

int main(void)
{
    struct node list =
        {.x = 10,
         .next = &(struct node){.x = 11,
                                .next = &(struct node){.x = 12,
                                                       .next = NULL}}};

    print_nodes(&list, stdout);
    return 0;
}

Neat! Clearly this is non-portable. It also is potentially unsafe since internally the compiler generates a bit of code on the stack and runs it. Still, the code looks nicer and we don't need cookies.