5

Is it possible to pass two lists to a sub in Perl, for example:

sub Foo {
 my(@list1,@list2) = @_;

}

I know I could make @_ two lists, with each sublist being the desired argument, I'm just wondering if there is a cleaner way

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Mike
  • 58,961
  • 76
  • 175
  • 221

2 Answers2

10

Well if you want two arrays you could use a prototype:

sub foo (\@\@) {
   my $arr1 = shift;
   my $arr2 = shift;

   # Access arrays as references
}

foo( @wiz, @waz );  # @wiz and @waz won't be flattened.

But there are many ways to get around prototypes, and I prefer to avoid them in most places. You can simply skip the prototype and manually pass references:

sub foo {
   my $arr1 = shift;
   my $arr2 = shift;

   # Access arrays as references
}

foo( \@wiz, \@waz ); # Pass in wiz/waz as refs
foo( [1,2,4],[3,5,6] );  # Hard coded arrays

If you haven't worked with references at all, check out perlreftut for a nice tutorial.

daotoad
  • 26,689
  • 7
  • 59
  • 100
  • it would seem that the prototype is a better solution, as it would not require the user to do anything special to pass the list arguments. thanks – Mike May 21 '10 at 17:12
  • 14
    @Mike, I would recommend against prototypes, since an experienced perl programmer will be more surprised by them than the requirement to pass a reference. Check out http://stackoverflow.com/questions/297034/why-are-perl-function-prototypes-bad for more on why prototypes are frowned upon. – daotoad May 21 '10 at 17:19
  • @Mike, I use prototypes soo often that I made an error in my prototype specification that I just realized. So if you already tried my code sample and it didn't work, note the change in the prototype. – daotoad May 21 '10 at 17:24
  • 4
    Indeed, prototypes are best avoided. You may also run into surprising results if you try to call a prototyped sub as an object method. – Ether May 21 '10 at 17:46
  • 2
    reference prototypes can be a bit annoying when you are trying to pass in a inline generated value without an intermediate array (output of `map` or `grep` for example). the non reference prototypes can be very useful though. the latter `foo` example can also be called this way: `foo \\(@wiz, @waz)` – Eric Strom May 21 '10 at 17:46
  • You have this really bad habit of highlighting the wrong answer by putting it first (and even mentioning it). – brian d foy May 22 '10 at 15:45
  • @Eric: maybe it's annoying because you're making it harder than it needs to be. Just use an anonymous array constructor around whatever is making the list: [ map {} ... ]. Easy Peasy. – brian d foy May 22 '10 at 15:46
  • @brian d foy => passing an anonymous array to a function with a `(\@)` prototype is a syntax error. It needs to be `@{[ map {} ... ]}` ... which ultimately doesn't help with readability and is just working around what should be an entirely unambiguous situation that the lexer/parser just doesn't understand. – Eric Strom May 22 '10 at 16:45
  • Well, that's one of the reasons you shouldn't use prototypes. I'm only talking about sane solutions. – brian d foy May 23 '10 at 02:10
5

If you pass two lists by value ... you're going to get one big list in @_.

my(@list1,@list2) = @_; doesn't make any sense:

#!/usr/bin/perl

sub test
{
    my (@a, @b) = @_;

    print "@a\n";
    print "@b\n";
}

my @array1 = (1,2,3);
my @array2 = (5,6,7);

test(@array1, @array2);

This will end up printing:

1 2 3 5 6 7
<blank line> 

To pass two arrays, you'd need to pass them by reference:

test(\@array1, \@array2);

And in your sub you'd need to treat them as references:

sub test
{
    my ($arrayRef1, $arrayRef2) = @_;
    print "@$arrayRef1\n";
    print "@$arrayRef2\n";
}
dave4420
  • 46,404
  • 6
  • 118
  • 152
Brian Roach
  • 76,169
  • 12
  • 136
  • 161