|
Arguments - Perl subroutine type-checking |
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:
/ (the
forward-slash character) is assumed to be the beginning of a regular
expression formed by appending that argument to qr. See
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+$/);
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 Package-specific Attribute Handling in the attributes manpage 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>.
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.
@{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.
sub (\@)).sub ($;$)).sub (%)).
B. K. Oxley (binkley) <binkley@bigfoot.com<
|
Arguments - Perl subroutine type-checking |