Closures and my all too close-minded understanding of them

18 05 2008

For the first time I’ve had to deal with marshallers or the concept of a closure. It’s quite an interesting topic that I know far too little speak about, except in the context of signals. GObject makes it pretty simple.

A Closure is essentially a closed packet of code, working in a confined environment, usually as a way of specifying a function used inside another function. For example, if you’re writing a sort function to sort a group of apples and oranges. The core of any sorting function is a comparsion between two objects. Now, comparing apples and oranges is a hotly debatable topic, so to keep your users happy, you’d like to have the user specify his view of how to compare the fruits. You’d write a function like this:

// In sort.c
void sort (AppleList *apples, OrangeList  *oranges, int (*compare_fn) (Apple, Orange))
{
// Blah blah
// Comparison step
switch (compare_fn (apple, orange)) {
case -1: // do something where apple < orange
case  0: // do something where apple == orange
case  1: // do something where apple > orange
}
// Blah blah some more
}
// In main.c
int i_like_apples (Apple *apple, Orange *orange)
{
/* Some complex association relation the size, smell, hex color values of the orange an apple ... or biased opinion. */
return 1;
}
int main () {
// The return of Blah blah
sort (list_of_apples, list_of_oranges, i_like_apples);
}

Here, the argument i_like_apples is a closure. It is an opaque block of code as far as sort is concerned. Languages like Python, Ruby or Lisp do this far more elegantly:

# in a module or at beginning of code
def sort (apple_list, orange_list, compare_fn):
# blah blah
if compare_fn(apple_list,orange_list) < 0:
# do something where apple < orange
else if compare_fn(apple_list,orange_list) == 0:
# do something where apple = orange
else if compare_fn(apple_list,orange_list) > 0:
# do something where apple > orange
# somewhere else
sort (list_of_apples, list_of_oranges, lambda apple, orange: 1)

There are apparently divisions among closures, and C/C++, Python don’t have ‘full closures’, while Ruby and most significantly, Lisp do. I don’t really know where that line is drawn, and as always, Wikipedia (http://en.wikipedia.org/wiki/Closure_(computer_science)) knows more than me. If I’m wrong anywhere though, please do correct me.

Advertisements

Actions

Information

3 responses

18 05 2008
Hal

Python is limited in its closures as functions created with the lambda keyword lambda in python can only be one line. You can’t return arbitrary procedures from procedures the way you can with lisp, perl & ruby.
Hal Abelson of “The Structure and Interpretation of Computer Programs” fame describes a closure as a means of combination where the objects being combined are closed. The example here is that a procedure can take as formal parameters, combine and return any arbitrary procedure. In python and more so in C this is not the case.

18 05 2008
arunchaganty

@Hal: Ok, I got that. I was thinking that there might be something a bit deeper. I’ve looked at the SICP (especially since it’s open now) videos. What an amazing professor! I envy those MIT students.

22 07 2008
Caleb

@Hal

That’s not entirely correct, or at least misleading. The lambda syntax is a special case. Closures can be created with regular function declarations in python, and are not restricted to use of lambda. This type of thing (i.e. this is pseudo-code, not working code) works fine in python:

x = 5
def MakeClosure(y):
def AnonMethod():
z = x*x + y*y {some arbitrary manipulation}
z = z / 2.0 {some more arb manip}
return z
return AnonMethod

You can certainly make closures of more than one line (or any other complexity), but then your function gets a name, as in above. As has been debated ad nauseum on the python newsgroup, having a name is not an impediment in and of itself, despite the “anonymous methods” label becoming fashionable recently (or the “lambda expressions” label having been fashionable for longer).

The restriction in python (as I understand it, ymmv) is that the closure cannot modify variables outside its scope, whereas several other FP languages can. This is a consequence of the implementation details of the locals() and globals() dictionaries, though I really can’t speak authoritatively on that, and you’ll have to look it up if you want the real facts.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: