Note: This article was written before D got full closure support.
Delegates are something that gives me mixed feelings. While I used to embrace them in Delphi and Object Pascal, I now find them difficult to get used to in C#. I guess that is because they introduce a little of the functional programming paradigm into an otherwise object oriented environment.
Don’t get me wrong, I do find delegates powerful and I use them whenever I see fit. It’s just that they bug me, like a badly-pitched note in an otherwise perfect chord. In that respect I am much more fond of the inner classes of Java.
The D Programming Language, my favorite pet at the moment, has support for both delegates and inner classes, thus providing the best of both worlds. And since D is a multi paradigm language with support for functional programming, its delegates are justified.
The semantics of D delegates are somewhat different from that of C#. For instance, C# delegates may bind to both static and non-static methods, while D may bind to non-static methods only. But on the other hand, D delegates may also bind to inner functions, which makes them look a lot like closures.
bool retry(int times, bool delegate() dg)
{
int tries = 0;
while (tries++ < times) {
if(dg())
return true;
}
return false;
}
// Example usage
retry(3, {
writefln("Password: ");
char[] buf = readln();
return (buf == "secretn");
});
In order to be a real closure a delegate is required to keep variables that are bound from the surrounding environment alive, even if the program has left their scope. For example, consider the following program.
int delegate() countdown(int from)
{
int current = from;
int countdown_helper() {
return current\-\-;
}
return &countdown_helper;
}
int delegate() dg = countdown(10);
dg(); // should return 10;
dg(); // should return 9;
dg(); // should return 8;
The countdown function returns a delegate that refers to the inner function countdown_helper. Counter_helper binds the variable current from it’s parent by returning its value and decreasing it by one.
So, if D’s delegates were real closures the first invocation of the delegate in the above example should return 10, the second 9, followed by 8, 7, and so on. But in reality they produce bogus values like 4202601 or 4202588. The reason is this: D doesn’t implement real closures. The variable current is invalid because the program is no longer executing the countdown function when countdown_helper is invoked via the delegate.
So D doesn’t have real closures, is that a big deal? No! In my opinion real closures are not important for languages that are not pure functional. The creators of D shouldn’t waste their resources on this feature since it brings little value but lots of implementation complexity. The energy is better spent on features like multicast delegates. Those would bring value in the form of convenience, and I hope future versions of D will incorporate them.
Complete versions of the code samples in this post can be found here and here.