Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

validating function input

by bobdeath (Scribe)
on May 21, 2003 at 16:15 UTC ( [id://259774]=perlquestion: print w/replies, xml ) Need Help??

bobdeath has asked for the wisdom of the Perl Monks concerning the following question:

I work for a company that is using perl for application development. I have found that several of the developers here are having problems with validating function/object input. What I am looking for is an easy way to validate that the correct number of arguments are being passed in, and possible do some kind of type validation. Any suggestions?

Replies are listed 'Best First'.
Re: validating function input
by Ovid (Cardinal) on May 21, 2003 at 16:20 UTC

    Correct number of arguments:

    sub foo { my $arg_count = 3; if ($arg_count != @_) { die "Incorrect number of arguments to foo"; } #... else do stuff }

    Validating the arugment types can vary tremendously depending upon what you want to do. You can read about parameter objects for this type of validation. The code is alpha, but it gives you an idea of how this can be done (it's also probably overkill for your needs). If it's OO code, you can try "Design by Contract", which is implemented in the Class::Contract module.

    Cheers,
    Ovid

    New address of my CGI Course.
    Silence is Evil (feel free to copy and distribute widely - note copyright text)

Re: validating function input
by perrin (Chancellor) on May 21, 2003 at 16:33 UTC

      I rate the Params::Validate module very highly. (Thank you, Dave Rolsky.)

      I've been using Params::Validate for a couple of months now, for a large project we're working on, and I've found it to be outstanding. Some things we like about it:

      • The interface is reasonably easy to understand, and the power it gives is very flexible.
      • It verifies all kinds of things: types (isa), interfaces (can), array refs, hash refs, regular expressions (use it with Regexp::Common!).
      • In addition, you can write your own validators.
      • In addition, you can turn it off (that is, turn the validation into a no-op) in production code, if you don't like the performance penalty.
      • The documentation is quite clear.
      • We've found that the validate(@_, ...) statements at the top of our functions form a very useful kind of API documentation. (I've been thinking about a way to automatically turn these statements into POD for documenting APIs.)

      It might be overkill depending on your application, but if you have a group of developers working together on something, it provides very a clear consistent way to enforce your expectations for a function's inputs.

        I rate the Params::Validate module very highly. (Thank you, Dave Rolsky.)

        You're welcome ;)

Re: validating function input
by halley (Prior) on May 21, 2003 at 17:20 UTC
    Before someone says, "use prototypes!" When to use Prototypes?

    I never use Perl's prototypes, and I'm a fair dinkum worried about Perl6's attempts to rectify their faults with a more complicated setup.

    --
    [ e d @ h a l l e y . c c ]

Re: validating function input
by Anonymous Monk on May 22, 2003 at 03:35 UTC
    Others have already pointed to modules, here is a simple, if eventually laborious, non-prototype solution:

    As already mentioned, evaluating @_ in scalar context will check the number of arguments, but you must remember that if a method is called on an object, @_ automatically receives as its first "argument" the object reference, which is why most methods start with the line my $self = shift which retrieves/removes the reference from the arg list.

    As for type validation, it depends what you mean. If you mean scalar/array/hash, then you can employ the ref() operator on each argument and compare the return value to what you expect, as in unless ref($arg1) eq 'HASH'... or whatever. For evaluating the type for object arguments, use the isa() operator, as in unless $self->isa(Bogus::Object).... isa() is superior to ref() in this context because it works with inheritance, returning true if the object IS-A instance of Bogus::Object or any of its children. Checking "types" any more pedantically (such as integer, string etc.) will involve using regexes (ugh) and if that's the case just use Java or something that has such support built into the language, or wait for Perl6.

Re: validating function input
by adamk (Chaplain) on May 22, 2003 at 11:02 UTC
    My answer applies only to OO stuff ( see above regarding when to use prototypes ).

    For objects, the ->isa method is commonly used to check "Is an object of this class".

    Of course, if you are taking arguments from outside the code you control, there's no way to know if ->isa will work, since isa'ing something that isn't an object will die.

    BUT, calling UNIVERSAL::isa as a function directly CAN handle non-reference arguments, and correctly returns false. ( i.e. UNIVERSAL::isa( undef, 'Something' ) works, and correctly returns false )

    I'm also a big fan of doing type checking ( where it doesn't get too large of course ) into the variable decleration. I'm also a fan of using return undef; to symbolise an error. Even in the cases where you have true/false responses, you can use true/false/undef ( 1/''/undef )

    SO, for most of my OO stuff, and there's a lot of it, I use something like the following.

    package Foo; use strict; sub bar { my $File = UNIVERSAL::isa( $_[0], 'IO::File' ) ? shift : return un +def; # Do something to file } 1;
    Of course, all those UNIVERSAL::isa's get virtually RSI like to type, so for convenience, I use the following.
    package Foo; use strict; use UNIVERSAL 'isa'; sub Foo { my $File = isa( $_[0], 'IO::File' ) ? shift : return undef; # Do something to the file } 1;
    I find this highly useful, especially for reasonably large quantities of arguments. Because you don't shift first and check later, you never forget to check.
      I should mention there is a variety of different uses for this as well.

      The most common are:

      sub foo { my $self = shift; # Is there a variable at all ( even undef ) my $anything = @_ ? shift : return undef; # Is there a defined argument my $def = defined $_[0] ? shift : return undef; # Is there a true argument my $true = $_[0] ? shift : return undef; # Is there an argument which conforms to a regex? my $re_ok = $_[0] =~ /^\w+$/ ? shift : return undef; # If the argument one of a limited number of values my $option = $_[0] =~ /^(?:this|that|foo|bar)$/ ? shift : return u +ndef; # Is it a reference my $ref = ref $_[0] ? shift : return undef;
      You get my point... it can be extended to cover most of the basics pretty well, and it probably much faster than calling to another subroutine.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://259774]
Approved by broquaint
Front-paged by tall_man
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (3)
As of 2024-04-26 06:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found