Arguments
Arguments - Perl subroutine type-checking
(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);
Arguments provides argument checking during compile and run time, supplementing prototype declarations.
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. :-)
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:
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
perlop/"qr/STRING/imosx" for details. Arguments to the sub call
are then checked against this pattern. An example:
sub eat_int_and_live ($) : Arguments (/^[+-]?\d+$/);
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.
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.
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.
None. However, Arguements pushes itself onto the caller's @ISA array so that the MODIFY_CODE_ATTRIBUTES technique may work. See attributes/"Package-specific Attribute Handling" for an explanation.
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 <perllexwarn>.
(F) Only hard references are allowed by strict refs. Symbolic
references are disallowed. See perlref.
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.
@{EXPR}. Hashes must be
%NAME or %{EXPR}. No implicit dereferencing is allowed--use the
{EXPR} forms as an explicit dereference. See perlref. For blessed
references, UNIVERSAL::isa ($_[%d], '%s') need be true.
sub (\@)).
sub ($;$)).
sub (%)).
B. K. Oxley (binkley) <binkley@bigfoot.com<