NAME Arguments - Perl subroutine type-checking SYNOPSIS (This documents version 0.2 of Arguments.) package Flintstone; use Arguments; BEGIN { $Arguments::ARGUMENT_CHECKS{INTEGER} = sub { defined $_[0] and $_[0] =~ /^[+-]?\d+$/ }, } sub fooby ($\%) : Arguments (INTEGER, HASH); sub tv_show ($) : Arguments (Flintstone); DESCRIPTION Arguments provides argument checking during compile and run time, supplementing prototype declarations. Why? There are other ways of doing this -- Damian Conway's Attribute::Handlers and Attribute::Types are one very interesting route; Dave Rolsky's Params::Validate is another. I am doubtful if I have covered the gamut with the mention of just those two. However, I had an epiphany to use subroutine attributes for argument type checking, and to try and make it clean and simple to use (DCONWAY's work is too general-purpose for my needs, and has a lot of overhead). It is not there yet, but I hope to get it there. If nothing else, it is a new, fun area of Perl for me to explore. An obvious area to explore is reimplementing this module using Attribute::Handlers and hooking in Params::Validate for richer type-checking. Maybe I'll do that after installing L4. :-) Basic Use To use Arguments, a sub declares an attribute named *Arguments* listing the type of arguments, each matching a protype declaration: sub fooby ($\%) : Arguments (INTEGER, HASH); By default, Arguments has only two checks: Regular Expressions Any argument to the *Arguments* attribute starting with a "/" (the forward-slash character) is assumed to be the beginning of a regular expression formed by appending that argument to "qr". See the section on "qr/STRING/imosx" in the perlop manpage for details. Arguments to the sub call are then checked against this pattern. An example: sub eat_int_and_live ($) : Arguments (/^[+-]?\d+$/); References (the default) Any other argument is assumed to be a reference checked by "UNIVERSAL::isa". This includes non-blessed reference types such as *HASH*. An example: sub eat_code_and_die (&) : Arguments (CODE); This example is unexciting since Perl's own prototype-checking should catch argument mismatches. Enforcing Method Calls A more interesting example enforces method calls: package Flintstone; sub yabba_dabba_doo ($) : Arguments (Flintstone); The creates a run-time check that the first argument to "yabba_dabba_doo" is indeed a "Flintstone" or a package which has "Flintstone" as a base. Presently, Perl has no way of enforcing this restriction. Extending Argument Checks Packages may extend the argument checks by manipulating %Arguments::ARGUMENT_CHECKS in their "BEGIN" blocks. An example: BEGIN { $Arguments::ARGUMENT_CHECKS{INTEGER} = sub { defined $_[0] and $_[0] =~ /^[+-]?\d+$/ }, } sub eat_int_and_live ($) : Arguments (INTEGER); This is the same as the example above for regular expressions, except that the intent of the sub declaration is more clear. EXPORT None. However, Arguements pushes itself onto the caller's @ISA array so that the MODIFY_CODE_ATTRIBUTES technique may work. See the section on "Package-specific Attribute Handling" in the attributes manpage for an explanation. DIAGNOSTICS The following are the diagnostics generated by Arguments. Items marked "(W)" are non-fatal (invoke "Carp::carp"); those marked "(F)" are fatal (invoke "Carp::croak"). None of the diagnostics may be selectively disabled with categores. See . Can't use string ("%s") as %s ref while "strict refs" in use (F) Only hard references are allowed by "strict refs". Symbolic references are disallowed. See the perlref manpage. What this usually means for Arguments is that you have a poorly formed argument list to the *Arguments* attribute such as "Arguments (Apple Core)" instead of "Arguments (Apple, Core)". (F) The function requires more arguments than you specified. Not enough prototypes for %s (F) The function requires more prototypes in the *Arguments* attribute than you specified. Too many arguments for %s (F) The function requires fewer arguments than you specified. Too many prototypes for %s (F) The function requires fewer prototypes in the *Arguments* attribute than you specified. Type of arg %d to %s must be %s (not %s) (F) This function requires the argument in that position to be of a certain type. Arrays must be @NAME or "@{EXPR}". Hashes must be %NAME or "%{EXPR}". No implicit dereferencing is allowed--use the {EXPR} forms as an explicit dereference. See the perlref manpage. For blessed references, "UNIVERSAL::isa ($_[%d], '%s')" need be true. TODO Tie type-checking of prototypes and attributes. Support for non-scalar prototypes (e.g., "sub (\@)"). Support for optional prototypes (e.g., "sub ($;$)"). Support for list prototypes (e.g., "sub (%)"). Generate prototype declarations from the attributes. Tests. AUTHOR B. K. Oxley (binkley)