http://qs321.pair.com?node_id=43323

When you have a function that has quite a few arguments, including a number of defaults, it is often much nicer to use a hash instead of an array. However a risk with that is that someone will mistype a name and their argument will be silently ignored. So ideally instead of just using a hash you want to do internal processing to make sure that the function has been called appropriately.

This snippet takes care of that. It allows you to have required arguments, optional arguments, and to set defaults on some of the optional arguments. Just use it like this:

sub examp_func { my %args = @_; my ($foo, $bar, $baz) = proc_args(\%args, ['foo'], ['bar', 'baz'], {bar => 'default'}); print "foo: $foo\n"; print "bar: $bar\n"; print "baz: $baz\n"; }
Unfortunately you still need to synchronize the order of arguments to the function with the variables that they go in. Barring using some sort of macro-preprocessing facility that looks unavoidable if you want the protection of lexical variables.

TIMTOWTDI, but if you are tempted to use this in a lot of your code you probably should think about whether certain collections of arguments logically belong together in an object of some class...

UPDATE
I am not longer happy with this snippet. The approach that I prefer as of Nov 2001 is in Re (tilly) 2: passing subroutine arguments directly into a hash. YMMV.

use Carp; # Takes an anon hash of args, an anon array of required fields, # an optional anon array of optional args, and an optional # anon hash of defaults. Returns an array of the determined # values sub proc_args { my $args = shift; my $req = shift; my $opt = shift || []; my $default = shift || {}; my @res; foreach my $arg (@$req) { if (exists $args->{$arg}) { push @res, $args->{$arg}; delete $args->{$arg}; } else { confess("Missing required argument $arg"); } } foreach my $arg (@$opt) { if (exists $args->{$arg}) { push @res, $args->{$arg}; delete $args->{$arg}; } else { push @res, $default->{$arg}; } } if (%$args) { my $bad = join ", ", sort keys %$args; confess("Unrecognized arguments: $bad\n"); } else { return @res; } }