Tuesday, October 31, 2006

The human compiler, #1

At it again... You want to get a sum over a subset of objects in a list. You don't want to iterate over the objects explicitly (as in for (ob = first_obj (list); ob; ob = next_obj (ob))), because that gets pretty annoying pretty soon, and also becomes interesting when you have to change that a bit for an explicit iterator state object.

Instead there is a function iter_list which calls a function of your for each object in the list, completely hiding the actual process of iteration. Unfortunately, now you need somehow pass your context into the callback function, and, being in C, iter_list accepts a separate parameter called userdata that it just passes to the callback for your use. Thus you do:

struct ctx {
  int sum;
  char *pref;
};
int cb (obj_t *obj, void *userdata) {
  struct ctx *cx = userdata;
  if (match (obj->name, cx->pref)) {
    sum += obj->count;
  }
}
int sum_prefixed (oblist_t *list, char *prefix) {
  struct ctx C;
  C.pref = prefix;
  C.sum = 0;
  iter_list (list, cb, &C);
  return C.sum;
}
Not quite amusing, because C does not have any local functions with lexical scoping. In a better language one could write
int sum_prefixed (oblist_t *list, char *prefix) {
  int sum = 0;
  int cb (obj_t *obj) {
    if (match (obj->name, pref)) {
      sum += obj->count;
    }
  }
  iter_list (list, cb);
  return sum;
}
The local function cbhas access to the variables surrounding its own definition. In essence the compiler now does what we did (pattern-like) above, by hand. To be even able to do the hand-trick, iter_list needs to have the third, pass-through, parameter; in the version where local functions are available this is no longer needed.

In fact the local function above works in Gnu C as shown as an language extension.

The next simplification would be to allow the function body directly in the place where it is needed, instead of defining a function and then using it's name:

int sum_prefixed (oblist_t *list, char *prefix) {
  int sum = 0;
  iter_list (list, int (obj_t *obj) {
    if (match (obj->name, pref)) {
      sum += obj->count;
    }
  });
  return sum;
}
The syntax gets a bit tricky here, but this is already very close to a form where iter_list looks like a real loop header construct. Alas, break won't work yet.

But since I have to use C in this project, I need to partially do the job of a compiler, and put down patterns again and again. Also, some languages spare me of actually declaring the type signature of the anonymous function and derive it from type of the argument for which it is used. That is called type inference, and in Java you would want it all the time, hypo.Wouldnt w = new hypo.Wouldnt () you?

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

Links to this post:

Create a Link

<< Home