Personally, I go with passing in hash refs most of the time, or shifting off when I only have a single parameter. And in all cases, I just deal with undefs as appropriate. Which sometimes means don't do anything about them - I want the fatal warning (I enable fatal warnings, too, did I forget to mention that?). If it's optional, I use the defined-or operator, // to use either the value or a default:
sub say_hello
{
my $opts = shift;
my $hello_sub = $opts->{hello_sub} // sub { my $o = shift; say "hell
+o, ", $o->{who} // 'world' };
$hello_sub->($opts);
}
say_hello(); # says "hello, world"
say_hello({ who => 'temporal'}); # says "hello, temporal"
say_hello({ hello_sub => sub { my $o = shift; say "wazzup, ", $o->{zup
+} // 'homie' }, zup => 'bro' }); # says "wazzup, bro"
Ok, so the example is getting a bit ridiculous, but you get the idea :-)
I don't check parameters. Almost ever. I've been bitten by too many tools trying to be too smart about their inputs, but when I feed them objects with string overloading or filehandles that aren't files and they fail just because the author didn't realise how automorphic perl variables can be, it gets annoying. Don't assume that the person calling your code is less smart than you. Carp if you have to, but it might just work if you try.