Reputation: 881273
In my code, I'm been using the fairly primitive method of extraction parameters from a function call as follows:
sub addSix ($$$$$$) {
my ($a, $b, $c, $d, $e, $f) = (shift, shift, shift, shift, shift, shift);
return $a + $b + $c + $d + $e + $f;
}
print addSix (1, 2, 3, 4, 5, 6) . "\n";
(forget the primitive code, the salient bit is the multiple shift
calls).
Now that seems rather messy to me and I though Perl may have something like:
my ($a, $b, $c, $d, $e, $f) = shift (6);
or something similar.
But I cannot find anything like that. I know I can use arrays for this but I think I'd still have to unpack the array into individual scalars. That wouldn't be too bad for the example case above, where the six parameters are similar, but I'm more interested in the case where they're not really suitable as an array.
How can you extract parameters without ending up with a morass of shift
keywords?
Upvotes: 18
Views: 39531
Reputation: 2297
I realise this is an old thread, but it got me thinking about a better way to shift multiple values. This is all just a bit of fun... Mainly posting this for educational purposes.
Sure, ($x, $y) = @_
is great if you want to retain @_
, but perhaps you want to shift your arguments for some reason? Perhaps you want any additional subroutine functionality determined by the number of remaining arguments in @_
.
The cleanest one-line way I could think of to do this is with a simple map
sub shiftySub {
map { $_ = shift } my ($v, $w, $x, $y);
# @_ now has up to 4 items removed
if (@_) { ... } # do stuff if arguments remain
}
@_
is now empty in the sub scope.@_
has 1 item remaining in the sub scope.@_
is empty, and $y
is undef
in the sub
scope.Regarding paxdiablo's theoretical shift(6)
operator, we could create our own function that performs this operation...
sub shifter (\@;$) {
my ( $array, $n ) = ( @_, 1 );
splice( @$array, 0, $n );
}
The function works by enforcing a pass-by-ref prototype (one of the very limited reasons you should ever use prototypes) to ensure the array gets shifted in the calling scope. You then use it simply like this...
my @items = ('one', 'two', 'three', 'four');
my ($x, $y) = shifter(@items, 2);
# or as a replacement for shift
my $z = shifter(@items)
# @items has 1 item remaining in this scope!
Of course, you could also use this shifter
function inside your other subs. The main downside to a function like this is you must keep track of the number of assignments on both sides of the operator.
I hope my $post = 'informative' || 'interesting';
Upvotes: 5
Reputation: 37136
The use of prototypes is highly discouraged unless there is a real need for it.
As always with Perl, there is more than one way to do it.
Here's one way to guarantee adding only the first six parameters that are passed:
use List::Util 'sum';
sub addSix { sum @_[0..5] }
Or if you like self-documenting code:
sub addSix {
my @firstSix = @_[0..5]; # Copy first six elements of @_
return sum @firstSix;
}
Upvotes: 7
Reputation: 206689
You can simply type:
my ($a, $b, $c, $d, $e, $f) = (@_);
If you didn't have that prototype, and if that sub got called with more than six arguments, the ones after the sixth are simply "not matched", $f
would be set to the sixth argument.
If you want to catch all the arguments after the sixth, you can do it like this.
my ($a, $b, $c, $d, $e, $f, @others) = (@_);
If your list of scalars is longer than the list on the right side, the last elements will be undef
.
Upvotes: 38