evan_tech

Previous Entry Share Next Entry
03:51 pm, 28 Sep 03

currying and callbacks

Curried functions (Schönfinkeled functions?) are common in more “theoretical” languages, but they’re approaching the mainstream, and will even be supported by Perl 6¹. From that article:
I remember saying almost exactly the same thing [it’s purely academic and not useful] about another language feature of ‘purely academic interest’ that got introduced with perl 5; the closure.
The rest of this assumes you know what a curried function is, so go read the first link if you don’t (it’s short).

Here is a (terrifying) Python implementation, which is complicated in part because of Python’s elegant keyword arguments. But as they point out there: it seems that curried functions are a (admittedly syntactically simpler) subset of closures. A Physical Example For Teaching Curried Functions shows a concrete example how currying might be useful, but then implements them using scheme closures.

One potential use of currying could be callbacks object-oriented programming. Here’s the setup: you want to be able to have callbacks call back into methods of your object, a situation that comes up pretty regularly on the GTK mailing lists, for example. Suppose you want to say in C++
somebutton.connect(“mouse-click”, this->on_mouse_click);
where “on_mouse_click” is some function of yours to be able to run code when they click on the button. Unfortunately, that function pointer is only a single pointer and it can’t include the address of “this” in it, so that code can’t work without some (pretty ugly) “closure” class that contains the function and the object (adding extra memory management complexity, too), and even then it currently escapes me how to make that work fully in C++ (though I know it’s possible).

When you have closures built into the language, the pattern is something like this (OO Perl might have some way to do this, but I don’t understand it well enough).
$somebutton.connect(“mouse-click”, sub { on_mouse_click($this) });
The closure contains the $this explicitly so it can be passed to on_mouse_click.
(I believe $this->on_mouse_click() is semantic sugar for on_mouse_click($this) in Perl, but there’s probably some extra stuff in there because of inheritance, etc.)

So how do other languages do it?

In Python, it appears that functions and methods are distinct entities:
>>> def a():
...   pass
...
>>> class Foo:
...   def a(self):
...     pass
...
>>> f1 = Foo(); f2 = Foo();
>>> f1.a; f2.a; Foo.a; a
<bound method Foo.a of <__main__.Foo instance at 0x30075968>>
<bound method Foo.a of <__main__.Foo instance at 0x30075918>>
<unbound method Foo.a>
<function a at 0x3006fc70>

where f1.a and f2.a are two distinct methods, which contain their objects. So you can pass around f1.a happily and it’ll always call the correct method.

Ruby has a (very interesting and useful, but a subject for another post) blurred distinction between mentioning and evaluating functions, so I can’t show similar code; there’s no way to refer to a particular function without calling it. (I say “particular function” because Ruby does have symbol objects that can be used to indirectly call functions, but symbols are global identifiers. Ruby is really weird in this area, anyway, so I’m not sure it’d be useful to compare; I think all toplevel functions are actually methods of the global “Kernel” object.)


In a curried language, you’d have functions like the Perl one, which take $self as their first parameter. (Here, for simplicity, I use an integer for the object, but something more complicated could be used, too.)
# let f this x y =
    (* do something with the parameters this, x, and y. *)
    this+x+y;;

but then you could partially evaluate them to get a method on a given object:
# let someobject = 42;;
val someobject : int = 42
# let method = f someobject;;
val method : int -> int -> int = <fun>

and then call that method directly
# method 3 4;;
- : int = 49


(Again, that’s ml code. jace, hopefully that’s more understandable than my last one?)
I really ought to read how ocaml does objects, though. They probably have cooked up something more clever. :)


1 The phrase “Perl 6 will support [x]” feels like a sort of tautology.