I maintain Data::FormValidator, which makes use of declarative programming. You provide a "profile" of how you want a form validated, and it takes care of the rest.

The common use of declarative programming is SQL-- you describe what you want out of the database and database system handles the rest.

In Perl, it's more natural to think of a declaration as a "profile" or "specification", so I'll use those words.

I find the concept very handy to apply in Perl because these specifications are often relatively compact data structures that are easy to scan, yet represent the intention of a complex series of actions.

By using a specification, all the customizations you want from a module are grouped in one place where they are easy to review and modify.

Here's an example of specification for CGI::Uploader: (some bits of this syntax are unreleased):

spec => { img_1 => { gen_files => { 'img_1_thmb_1' => gen_thumb({ w => 100, h => 100 }), 'img_1_thmb_2' => gen_thumb({ w => 50, h => 50 }), } + }, },

I've compactly represented that I want to upload one image and from it generate two different thumbnails of different sizes.

The benefit of closures

I want to explain how the gen_thumb() call here works, because it's a uncommon technique that is the crux of building powerful and easy to use declarative interfaces.

The problem is here is that as part of declaring the spec I want to refer to arbitrary chunks of code to transform file uploads, and I want these code references to have options, but I don't have all the data I need to pass into the routine--- we won't get that until the spec is actually used later.

In this case, gen_thumb() also needs at least a file name as input so it has a file to transform. However, you can see that no file name is passed into the function.

A peek inside

What happening is that gen_thumb() is being executed immediately as it would appear to be, but all it does for the moment is to return a custom-built subroutine to be called later. Sort of like this:

sub gen_thumb { my %args = @_; return sub { my $self = shift; my $filename = shift; _really_gen_thumb($self, { filename => $filename, %args, }); } }

So we're building the function we'll need later but not actually executing it. The function is designed to receive the object and filename that it will receive later, and blend them with the arguments its getting now.

The ugly alternative

Without using the technique, declarative programming in Perl can become awkward. To illustrate, Here's what the same CGI::Uploader spec looked like before I had this conceptual breakthrough.

spec => { img_1 => { gen_files => { 'img_1_thmb_1' => { + transform_method => \&gen_thumb, params => [{ w => 100, h => 100 }], + } + 'img_1_thmb_2' => { + transform_method => \&gen_thumb, params => [{ w => 50, h => 50 }], } + } + }, },

It worked, but it was unnecessarily unwieldy.

Going further

If functions that generate other functions interest you, I recommend the book Higher Order Perl, which illustrates several other uses besides declarative programming.

Replies are listed 'Best First'.
Re: CGI::Uploader: Using closures to improve a declarative interface.
by radiantmatrix (Parson) on Dec 19, 2005 at 15:14 UTC

    How is your new method different from?:

    spec => { img_1 => { gen_files => { img_1_thmb_1 => sub { gen_thumb({w=>100, h=>100}) }, img_1_thmb_2 => sub { gen_thumb({w=>50, h=>50}) }, } } }
    I guess I don't quite understand...
    <-radiant.matrix->
    A collection of thoughts and links from the minds of geeks
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law
      It's better syntax and good policy to remove unimportant stuff.
      More importantly, you don't force the user to understand anonymous subs, which are an advanced topic.

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

      That new version still doesn't pass the filename on to gen_thumb...unless I missed something. So its different because its not the same? More simply, gen_thumb is returning a subroutine with the width and heigth already set. That new routine is then passed the filename when its time to actualy generate the thumbnail. /me wonders then if closures are just another way to achieve function currying.


      ___________
      Eric Hodges $_='y==QAe=e?y==QG@>@?iy==QVq?f?=a@iG?=QQ=Q?9'; s/(.)/ord($1)-50/eigs;tr/6123457/- \/|\\\_\n/;print;
Re: CGI::Uploader: Using closures to improve a declarative interface.
by revdiablo (Prior) on Dec 19, 2005 at 17:48 UTC

    Nice post. I like this idea; it makes for nice looking and simple code at the user level, yet allows for a good bit of power behind the scenes.

    One thing I noticed though. You're passing a hash reference, but accessing it as if it's a list of key-value pairs with my %args = @_. Am I missing something here, or is it just a small bug? Lord knows I've had that bug before, which is the reason I noticed it.

      Although it's pseudo-code-- yes there was a bug there.