http://www.perlmonks.org?node_id=284847
Foggy Bottoms has asked for the wisdom of the Perl Monks concerning the following question:

Dearest monks of far and wide,

As you may know when one writes a sub, he/she can send parameters to that sub and one of the most convenient ways to retrieve those parameters is by using the tool shift...

One question has been puzzling me however... Let's take for example the following sub :
sub test { my $number = shift; my @array1 = shift; my @array2 = shift; # do your stuff } ........................ my @a = ("mary","had","a","little","lamb","!"); my @b = ("London","Bridge","is"); # call sub test(3,@a,@b);
How does the sub manage to figure out what's the size of @a and @b so that when you use the shift tool you don't end up with @array1 being ("mary","had","a","little","lamb","!","London","Bridge","is"); and @array2 nothing...

Surely this is a trivial question and I'm probably overlooking something important - but I'm still quite intrigued. Could someone please enlighten me ?

Replies are listed 'Best First'.
Re: Parameters, subs and the shift function
by Abigail-II (Bishop) on Aug 19, 2003 at 11:08 UTC
    Parameters to a function get flattened to a single list. If you call a sub as test (3, @a, @b), then inside test you can't distinguish what came from @a and what from @b. If you want to pass entire arrays, you will have to pass references, and deal with references in the function.
    sub test { my $number = shift; my @array1 = @{+shift}; # Shift off the reference, and derefe +rence it my @array2 = @{+shift}; # Do your stuff } test (2, \@a, \@b);

    Abigail

      Abagail-II, what is the signifigance of the + in the shift statements? Why is this a good thing to do?
      my @array1 = @{+shift}; my @array2 = @{+shift};
      Thanks,
      Tim
        Run it under strict, and try it without the +. The error message you get will enlighten you.

        Abigail

Re: Parameters, subs and the shift function
by edan (Curate) on Aug 19, 2003 at 11:15 UTC

    You went to the trouble of writing some nice test code, but did you run it? It might help answer some of your questions...

    First, shift only takes one element off the parameter list, so your test sub will give you:

    $number = 3; @array1 = ("mary"); @array2 = ("had");

    As for how the arguments are passed to the function, perl flattens out the argument list, so it will arrive as one big list (@_ to be exact), and you won't be able to tell where one list end and another begins. If you need to do this, you'll have to pass references, like so:

    sub test { my $number = shift; my $arrayref1 = shift; my $arrayref2 = shift; # remember to dereference: @$arrayref1 etc. } # ......... my @a = ("mary","had","a","little","lamb","!"); my @b = ("London","Bridge","is"); # call sub test(3,\@a,\@b);

    HTH

    --
    3dan
Re: Parameters, subs and the shift function
by larsen (Parson) on Aug 19, 2003 at 11:08 UTC
    How does the sub manage to figure out what's the size of @a and @b so that when you use the shift tool you don't end up with @array1 being ("mary","had","a","little","lamb","!","London","Bridge","is"); and @array2 nothing...
    No way. See "Pass by reference" in perlsub.
Re: Parameters, subs and the shift function
by CombatSquirrel (Hermit) on Aug 19, 2003 at 12:16 UTC
    Just one thing to add to what the others said: Although discouraged by some, I personally fancy prototypes. In the following example prototyping the function makes it seem (this "seem" is important) as if you just needed arrays and not references to arrays; the references are automatically generated by Perl.
    #!perl use strict; use warnings; sub test ($\@\@) { my $number = shift; my @array1 = @{+shift}; # Shift off the reference, and dereference + it my @array2 = @{+shift}; # Print the variable contents print $number . $/ . join(' - ', @array1) . $/ . join(' - ', @array +2) . $/; } my @a = qw(mary had a little lamb !); my @b = qw(London Bridge is); test (2, @a, @b); __END__ OUTPUT: 2 mary - had - a - little - lamb - ! London - Bridge - is
    Have a look at perlsub for an explanation of prototypes. Please note that the above only works for arrays and not for lists.
    Hope this helped.
Re: Parameters, subs and the shift function
by davorg (Chancellor) on Aug 19, 2003 at 14:13 UTC
    How does the sub manage to figure out what's the size of @a and @b

    It doesn't

    Update: Yes, as 3dan points out below, there was some incorrect nonsense in this node for about 30 seconds after I posted it. When I realised my error I removed it immediately. Sorry for any confusion caused.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      Update: This node is in response to davorg's post, which he has subsequently updated by removing the offending material, so this response as well as the response of Foggy Bottoms becomes garbage. I think in the future, davorg, you should strike out or otherwise update your node, instead of just deleting material that people have already related to.

      so that when you use the shift tool you don't end up with @array1 being "mary","had","a","little","lamb","!","London","Bridge","is"); and @array2 nothing...

      With your code, that's exactly what would happen.

      No, you're wrong. shift returns the first value in the flattened argument list each time it is called, and removes it, so @array1 will be ("mary"), and @array2 will be ("had"). If the code would have been written like this:

      my ($number, @array1, @array2) = @_;

      ... then you'd be right.

      --
      3dan
      That's not what I understand from what 3dan said, so I'm a bit puzzled. Anyway, I updated my code and the arrays work fine now (cuz I actually had the problem but since I hadn't bothered printing out @array1 and @array2 I hadn't noticed the error, not until I felt the urge to satisfy my curiosity and ask the question here...)
      Thanks