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; } }

In reply to Handling named function arguments by tilly

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.