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 toqr
. See "qr/STRING/imosx" in perlop 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 "Package-specific Attribute Handling" in attributes 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 <perllexwarn>.
- 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 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 ofArguments (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 perlref. 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) <binkley@bigfoot.com<
SEE ALSO
- Attribute::Handlers
- Attribute::Types
- "isa ( TYPE )" in UNIVERSAL
- attributes
- "qr/STRING/imosx" in perlop
- perllexwarn
- perlref
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 427:
=over without closing =back