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.
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.
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.
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.
|
|---|
| 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 | |
by diotalevi (Canon) on Dec 19, 2005 at 15:54 UTC | |
by dragonchild (Archbishop) on Dec 19, 2005 at 16:34 UTC | |
by eric256 (Parson) on Dec 19, 2005 at 17:18 UTC | |
|
Re: CGI::Uploader: Using closures to improve a declarative interface.
by revdiablo (Prior) on Dec 19, 2005 at 17:48 UTC | |
by markjugg (Curate) on Dec 20, 2005 at 00:50 UTC |