Full closures for D

David B. Held dheld at codelogicconsulting.com
Tue Nov 6 22:44:46 PST 2007


Ok, everyone knows that closures are cool (and those that don't know 
will soon see), so let me see what y'all think about this proposal...

Now Perl has extremely compact closures because of the special $_ and @_ 
variables that can be used to refer to the function arguments.  Just the 
other day, I wrote this handy bit of code which converts relative 
directory entries into absolute pathnames:

    my $base = "/path/to/dir/";
    my @absoluteDirs = map { $_ = $base . $_ } readdir DIR;

Whatever you think about Perl, you have to admit that this is some 
pretty sweet code.  It's about as pure as Haskell (well, obviously I'm 
modifying $_, so it's not 'pure' in the literal sense), modulo Perl's 
syntax.  Let's look at the old imperative way to do this:

    string base = "/path/to/dir/";
    string[] absoluteDirs;
    foreach (file; readdir(DIR))
    {
        absoluteDirs ~= base ~ file;
    }

This really isn't too bad, and some folks might even prefer this style, 
but when the closure variables become lengthy expressions, this becomes 
more verbose.  Note that we have to repeat absoluteDirs and file, but 
thank D that we don't have to spell out a bunch of extraneous types or 
loop mechanics.

Now given some suitable definitions (which I demonstrate at the bottom), 
this is what we can do in D, with Walter's new closures:

    auto base = "/path/to/dir/";
    auto absoluteDirs = map((string file) { return base ~ file; }, 
readdir(DIR));

We don't have to repeat absoluteDirs, but we still have to repeat file. 
  Still, this is pretty darned close to the Perl form, so I think we're 
doing pretty well.  However, I think it would be nice to get rid of the 
delegate type declaration altogether and git ourselves an implicit 
delegate argument, like so:

    auto base = "/path/to/dir/";
    auto absoluteDirs = map({ return base ~ $0; }, readdir(DIR));

Notice that this is just about as close to the Perl/Haskell form as D is 
likely to ever get.  And it's a thing of beauty.  Of course, this is a 
small (but real) example, so it doesn't fully illustrate the utility of 
implicit lambda args, but don't you agree that this would be cool?

Dave



----------8<----------Proof of Concept---------------8<---------------
module Test;

import std.stdio;

string[] readdir(string dir)
{
    return ["foo", "barz", "bazzz"];
}

T[] map(T)(T delegate(T) f, T[] list)
{
    T[] result;
    foreach (e; list) result ~= f(e);
    return result;
}

void main()
{
    auto base = "/path/to/dir/";
    writeln(
        map((string file) { return base ~ file; }, readdir(""))
    );
}



More information about the Digitalmars-d mailing list