Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Re: How to pass two lists to a sub?

by Prior Nacre V (Hermit)
on Nov 05, 2004 at 12:06 UTC ( [id://405474]=note: print w/replies, xml ) Need Help??

in reply to How to pass two lists to a sub?

To do this, pass references to the arrays and dereference in the subroutine:

process_something($scalar1, $scalar2, \@list1, \@list2); sub process_something { my ($scalar1, $scalar2, $ra_list1, $ra_list2) = @_; my @list1 = @$ra_list1; my @list2 = @$ra_list2; }

Another way is to pass all parameters in a hashref:

my $rh_params = { scalar1 => $scalar1, scalar2 => $scalar2, list1 => \@list1, list2 => \@list2, }; process_something($rh_params); sub process_something { my $rh_params = shift; my $scalar1 = $rh_params->{scalar1}; my $scalar2 = $rh_params->{scalar2}; my @list1 = @{$rh_params->{list1}}; my @list2 = @{$rh_params->{list2}}; }

The second method involves more coding but provides a number of benefits:

  • No more concerns about getting parameters in the right order
  • Any, or all, parameters can be optional with the subroutine setting defaults for missing keys
  • Add or remove parameters without changing the subroutine signature
  • It also affords a certain degree of data encapsulation

Update: Added missing line: process_something($rh_params);



Replies are listed 'Best First'.
Re^2: How to pass two lists to a sub?
by hmerrill (Friar) on Nov 05, 2004 at 12:36 UTC
    A few things - mostly just personal preference.

    I prefer to use the "shift" function, like this:

    sub process_something { my $s1 = shift; my $s2 = shift; my $arrayref1 = shift; my $arrayref2 = shift; # And instead of creating new hashes from the # references passed in... #my @array1 = @$arrayref1; #my @array2 = @$arrayref2; # You can use the references themselves... # like $arrayref->[i] below... print "Subroutine process_something: \$s1 = $s1\n"; print " \$s2 = $s2\n"; my $count_array1_elements = @$arrayref1; for ($i = 0; $i < $count_array1_elements; $i++) { printf "Array1 Element %d = %s\n", $i, $arrayref->[i]; } } process_something($scalar1, $scalar2, \@array1, # pass a *reference* to the array \@array2); # same

      Personal coding preferences aside, I did consider something along the lines you have here but decided against it for two reasons.

      1. YAFZ asked specifically for arrays: "All I need is a simple construct in which I'll have two correct @l1 and @l2 at the end."
      2. Some benchmarking I carried a few months ago indicated that evaluating $array[$i] was faster than evaluating $arrayref->[$i]. (As one might expect given the additional dereference operation.)

      (Minor point: You have $arrayref->[i] in a number of places.)



        Some benchmarking I carried a few months ago indicated that evaluating $array[$i] was faster than evaluating $arrayref->[$i].

        I am not trying to say your benchmark is wrong, and I don't want to say there are no applications where this would make a difference, but using this as a general rule of thumb does not strike me as a good idea. I would be very surprised if most, or even many, applications would benefit from this kind of nano-optimization.

        More generally, this type of benchmarking is almost always pointless. Using it in isolation to determine the semantics of your code is, frankly, silly. There may be cases where these types of small optimizations add up to real savings, but those are the exception, not the rule. Contorting your code for the exception, without knowing if you are truly hitting that exception, is a waste of time and effort.

      I prefer to use the "shift" function

      I think using shift to pull in arguments is occasionally warranted, but it should be avoided most of the time. My reasons are as follows:

      • It's less maintainable. To add a new argument, you either have to copy and paste the shift line, and modify the variable name, or you have to retype essentially the same thing each time. These are both error-prone processes. Error-prone processes should be avoided whenever possible.
      • Each shift modifies the @_ array. My concern with this is not about performance (see a related post), but about semantics. Sometimes it makes sense to modify the array, and in those cases I use shift. But usually you are just trying to copy the arguments into more convenient variable names, and that does not necessitate the destruction of the array.

      Accessing @_ directly does not have these problems. Using the common construction my ($foo, $bar, $baz) = @_; makes it easy to add new arguments, and it does not mangle @_ as a side-effect. I would be interested to hear your reasons in favor of shift-by-default, because, to me, the reasons against it are pretty convincing.

        The main reason I use shift over @_ is to easily set up defaults and quickly get some error checking out of the way.
        my $var1 = shift || 'default'; my $var2 = shift || return 0;
        I respectfully disagree with both points.

        I disagree that shift makes code less maintainable. I agree that you are forced to change the code when a parameter is added, but I'm hard-pressed to come up with any situations where adding parameters _shouldn't_ warrant changing the code. If you are changing what is coming in to a subroutine, are you not changing the function of the subroutine??? Being explicit about exactly what parameters a subroutine takes in is just being clear - in my mind that makes the code _more_ maintainable.

        For what reason would you want to maintain the original @_ array? I can't see any reason that maintaining the original argument array has any advantage over individual arguments created by shift. I don't typically (ever?)change the values of parameters taken into a subroutine anyway (does anyone else?) so maintaining the original parameter list is really no different with shift than it is with assigning variables from @_.

        Feel free to disagree with me - for now I can't see any merit to your exceptions to using "shift'.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://405474]
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (6)
As of 2024-05-22 01:07 GMT
Find Nodes?
    Voting Booth?

    No recent polls found