Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Params::Validate - a powerful tool for robust subroutine design

by santonegro (Scribe)
on Jan 22, 2006 at 01:21 UTC ( #524718=perlmeditation: print w/replies, xml ) Need Help??

I am very pleased with Params::Validate. Why?

Goodbye ||=, Goodbye ref $x eq 'ARRAY'

I'm sure we've all seen subroutines like this:
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.

Hello infinitely extensible subroutines

With standard Perl subroutines, the calling order is significant and things get icky if you want to tack on a mandatory parameter later: you either rewrite all the code and put this new mandatory parm before the optional ones or write a new function.

Not so with PV. You just validate on one more parameter and specify that it is mandatory.

Named arguments

Named arguents are somewhat self-documenting in the calling code. Not only that, but they shuttle quite nice to and fro, hashes being the lingua franca between many external input and output sources. With Params::Validate, you typically operate in named parameter mode. I've never used it's positional verification. Also, the two largest distributions using PV (Mason and Alzabo) both use named parameters as well. But, if you want to go the positional route, PV is right there with you.

Hello easy and confident documentation of function input

It is nice when one line of the data validation maps to one English sentence. It makes it much easier to document functions. For example, here is a sub that I added to HTML::Element::Library today:
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 tag +s 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}

Summary

use Params::Validate;

See Also

Params::Validate review by rinceWind

Replies are listed 'Best First'.
Re: Params::Validate - a powerful tool for robust subroutine design
by radiantmatrix (Parson) on Jan 23, 2006 at 17:31 UTC

    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.

    <-radiant.matrix->
    A collection of thoughts and links from the minds of geeks
    The Code that can be seen is not the true Code
    I haven't found a problem yet that can't be solved by a well-placed trebuchet

      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!

        <-radiant.matrix->
        A collection of thoughts and links from the minds of geeks
        The Code that can be seen is not the true Code
        I haven't found a problem yet that can't be solved by a well-placed trebuchet
Re: Params::Validate - a powerful tool for robust subroutine design
by autarch (Hermit) on Jan 24, 2006 at 07:16 UTC

    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]).

A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://524718]
Approved by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2021-11-27 18:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?