sub greet {
my ($name, $age) = @_;
# required param
$name or die "must supply name" ;
# optional param, defaults to 25
$age ||= 25;
print "Hello, there $name. How does it feel to be $age?\n";
}
Well, try this out for size:
use Params::Validate qw(:all);
sub greet {
my %p = validate(@_, {
name => 1, # required
age => { default => 25 }
})
}
print "Hello, there $name. How does it feel to be $age?\n";
Personally I like the Params::Validate solution. No, let me take that
back... I LOVE the Params::Validate solution. It is
much more definitional. This may not seem like a big win with
just two parameters but when you get 8 parameters, such as in
the table2() function that I recently wrote, it really begins to pay off.
You have one part of your code that serves as a "firewall" making sure that everything the function requires is there and of the right type. And any optional things get their default values. It is a huge headache saver.
Not so with PV. You just validate on one more parameter and specify that it is mandatory.
sub HTML::Element::iter2 {
my $tree = shift;
my %p = validate(
@_, {
# the container look-down. defaults to ['_tag' => 'dl']
wrapper_ld => { default => ['_tag' => 'dl'] },
# the data to fill the container with. mandatory
wrapper_data => 1,
# the routine to preprocess the HTML::Element container
# by default no preprocessing is done
wrapper_proc => { default => undef },
# the routine to find the "templated" sub-elements of container
# by default returns an arrayref consisting on the dt and dd tags
item_ld => { default => sub {
my $tree = shift;
[
$tree->look_down('_tag' => 'dt'),
$tree->look_down('_tag' => 'dd')
];
}
},
# the routine to return a row of data from wrapper_data
# the default routine simply shifts off a row. you might
# replace this with $wrapper_data->next in some cases
item_data => { default => sub { my ($wrapper_data) = @_;
shift(@{$wrapper_data}) ;
}},
# the routine to take the row of data and populate the item tags
# the default routine takes a two-element array and fills the
# dt and dd tags
item_proc => {
default => sub {
my ($item_elems, $item_data, $row_count) = @_;
$item_elems->[$_]->replace_content($item_data->[$_]) for (0,1) ;
$item_elems;
}},
# the routine to place the accumulated item rows back in the the
# HTML::Tree. By default removes the two sample rows (dt and dd)
# and replaces them with all the item rows
splice => { default => sub {
my ($container, @item_elems) = @_;
$container->splice_content(0, 2, @item_elems);
}
},
# output debug info? by default, no
debug => {default => 0}
I'm a big fan of Params::Validate myself. Like most things, though, there is a drawback. I converted an entire project (about a dozen modules and two scripts) to using Params::Validate in preparation for handing it off to another developer who was to use the modules in new scripts.
The upside: the developer was able to code more quickly to my interface because he got very clear error messages when invalid params were passed.
The downside: after conversion, the original scripts ran more slowly. Noticably, but acceptably.
Of course, in many cases the performance difference will not matter compared to the advantages. That doesn't stop me from wishing I had the time to write a Params::Validate_XS. And, since a number of things I write *do* have to consider per-subroutine-call performance, I end up using the existing Params::Validate a lot less often than I'd like.
Params::Validate *is* in XS. When you install it, it'll build the XS version if you have a compiler. When you run it, it'll load the XS version if it is available.
⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊
I'm sure it'd be possible to eek out a little more speed from the existing code, but I suspect that absent language-level support for this sort of stuff, it's not going to get a whole heck of a lot faster.
Perl6 looks to have pretty nice parameter declaration capabilities, so I'm hoping that most, if not all of what I have to do with Params::Validate now I can do natively in Perl6.
Hm, as my exposure to the module has only been in Win32 on ActiveState, I didn't notice any compiling. It looks like my particular install was borked, as the ValidateXS.pm was missing. A reinstall has restored that file and allowed an impressive speed boost.
Thanks for pointing that out, or I would never have found this issue!
One style note I'd like to make. At $DAYJOB other coders liked the concept of declaring an API and checking it, but they felt like having a big clock of param spec code in the subroutine body was distracting, especially for short subs.
I've started using this style whenever possible to work around that problem:
{
Readonly my $spec => {
size => { type => SCALAR },
color => { type => SCALAR,
regex => qr/^(?:red|green|blue)$/i },
};
sub item_by_size_and_color {
my %p = validate( @_, $spec );
...
}
}
This pulls the parameter declaration out of the sub body but puts it right next to the sub. The use of Reaodnly is entirely optional, and I should point out that it only works with the XS version of Readonly, the pure Perl version will cause segfaults if you use the XS version of Params::Validate (perl magic in the internals is a huge PITA for XS code).
Generally speaking, I'm really liking the above style, though if you need to calculate some part of the spec dynamically per request, it won't work.
We also created a library to simplify "type declaration", so we have code like this:
{ size => SCALAR_TYPE,
color => RGB_COLOR_TYPE( default => 'blue' ),
...
}
I'd like to turn this into a CPAN module eventually, maybe something like Params::Validate::Types.
And finally, it's worth noting that Params::Validate is fairly flexible in its inputs. The parameters can be given as a hash (in @_) or a hashref (in $_[0]).
Perl Best Practices does not recommend Params::Validate
Ah... argument from authority. Gotta love it. So pure, so simple.
perlmonks.org content © perlmonks.org and Anonymous Monk, Aristotle, autarch, diotalevi, jdporter, radiantmatrix, rhesa, santonegro, shenme
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03