SPUG: argument-less shift - explicit/implicit [was: Hashes and subroutines]

Jack Foy jack at foys.net
Wed Jan 7 20:55:00 PST 2009


Michael R. Wolf wrote:
> Jack Foy wrote:
> >sub runCommand {
> >	my $command = shift;
> >	my $rArgs = shift;	# or use @_, but see note 1
> 
> This seems backwards to my way of thinking (i.e. my way of reading and  
> writing code for my own and other's use):
>     You use @_ *implicitly*, but state that *explicit* code is easier  
> to read.

You're right, I was unclear.  I meant, it's more explicit to call our
hypothetical routine like so:

	runCommand ($command, \@commandArgs);

rather than something like this:

	runCommand ($command, @commandArgs);

You gave one example of how that might be implemented:

> sub xxx {
>     my ($first_arg, $second_arg, @remaining_args) = @_;
> }

I avoid that approach because it makes it much more expensive to pass
around and manipulate large data structures (by requiring a copy of
every element of @remaining_args).

The alternate implementation I was thinking of, but advised against, was
to pass the remaining elements of @_ through to the selected caller:


sub runCommand {
        my $command = shift;

        my %actions = (
                play    => \&sub1,
                that    => \&sub2,
                funky   => \&sub3,
                music   => \&sub4,
        );

        my $rAction = $actions{$command}
			or return LogError ("Unknown command '$command'");

        return &$rAction (@_);
}


That's a perfectly acceptable alternative, especially if you want the
routine selected from the table to behave (almost) as though it were
called directly by runCommand()'s caller.  But it carries the twin costs
of obscuring the interface to runCommand(), and exposing the original
arguments to runCommand() to @_'s aliasing behavior.

By the way, note that a further alternative is to use the "magic goto":


sub runCommand {
        my $command = shift;

        my %actions = (
                play    => \&sub1,
                that    => \&sub2,
                funky   => \&sub3,
                music   => \&sub4,
        );

        my $rAction = $actions{$command}
			or return LogError ("Unknown command '$command'");

        goto &$rAction;
}


This really does behave as though the caller to runCommand() actually
invoked the selected caller directly!  It replaces runCommand() with the
selected routine on the call stack, with @_ as the argument.  There are
rare times when this is the Right Thing.  Use with appropriate caution.

-- 
Jack Foy <jack at foys.net>


More information about the spug-list mailing list