Named Parameters - Page 12
July 13, 2001
Unlike other languages such as C or Java, Perl does not have any
way to define formal parameter names for subroutines. The closest
it gets is prototypes combined with retrieving parameters as
lexical variables, as in:
sub surname {
my ($scalar1, $scalar2, @listarg) = @_;
...
}
However, we can implement named parameters using a hash. This
provides an elegant way to pass in parameters without having to
define them formally. The trick is to assign the @_
array to a hash variable. This converts the passed list into key-
value pairs:
sub volume {
my %param = @_;
return $param{'height'} * $param{'width'} * $param{'length'};
}
The disadvantage of this approach is that we have to name all the
parameters that we pass. It is also slower, since hashes are
inherently slower than arrays in use. The advantage is that we
can add more parameters without forcing the caller to supply
parameters that are not needed. Of course, it also falls upon us
to actually check the arguments passed and complain if the caller
sends us arguments that we do not use.
We can call this subroutine using the =>
operator to make it clear that we are passing named parameters:
volume (height => 1, width => 4, length => 9);
We can also write the subroutine so that it accepts both named
parameters and a simple list. One common technique borrowed from
UNIX command line switches is to prefix named arguments with a
minus, to distinguish them from unnamed arguments. To determine
how the subroutine has been called, we just check the first
character of the first parameter to see if it is a minus:
sub volume {
my %param;
if ($_[0]=~/^-/) { # if the first
#argument starts '-', assume named
# arguments
while (@_) {
my ($key, $value)=(shift, shift);
# check all names are legal ones
die "Invalid name '$key'"
if $key!~/^-(height|width|length|color|density)$/;
$key =~ s/^-//;
#remove leading minus
$param{$key} = $value;
}
} else {
# no '-' on first argument - assume list arguments
$param{'height'} = shift;
$param{'width'} = shift;
$param{'length'} = shift;
}
foreach ('height', 'width', 'length') {
unless (defined $param{$_}) {
warn "Undefined $_, assuming 1";
$param{$_} = 1;
}
}
return $param{'height'} * $param{'width'} * $param{'length'};
}
In this version of the volume subroutine we handle
both simple and named parameters. For named parameters we have
also taken advantage of the fact that we know the names of the
parameters to report a handy informative warning if any of them
are undefined.
Named parameters allow us to create a common set of parameters
and then add or override parameters. This makes use of the fact
that if we define a hash key twice, the second definition
overrides the first:
# define some default parameters
%default = (-height => 1, -width => 4, -length => 9);
# use default
print volume(%default);
# override default
print volume(%default, -length => 16);
print volume(%default, -width => 6, -length => 10);
# specify additional parameters
print volume(%default, -color => "red", -density => "13.4");
Converting Scalar Subroutines into List Processors - Page 11
Professional Perl Programming
Named Parameters: Additional Information - Page 13
|