Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Best practices for passing in function arguments?

by andrewkl (Novice)
on Dec 09, 2015 at 19:31 UTC ( [id://1149817]=perlquestion: print w/replies, xml ) Need Help??

andrewkl has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

Can someone please tell me which scenario is the best practice in terms of passing args to a function?

In Scenario 1, foo() calls bar() with a reference to an array that contains only 1 item (that item is a ref to a hash).

In Scenario 2, foo() calls bar() with a reference to a hash array.

Does it make sense to pass in an array that contains only one item (a ref to a hash)? That array will always have only 1 item.
Or is it better to directly pass in the hash array (Scenario 2) ?

Thanks
--Andrew

///////////////////////////////////////////////////////////
#### Scenario 1:
sub foo { my @arr = (); my %hash = (); .... %hash = .... # key/values populated by some API push(@arr, \%hash); bar(\@arr, <other_args>); # @arr contains only one item } sub bar { my $array_ref = shift; .... other function args are accessed here foreach my $i (.....) { .... %some_hash initialized here for each iteration of the for +-loop push (@$array_ref, \%some_hash); } zzz($array_ref); # zzz() will do some read-only operations with +this array }
////////////////////////////////////////////////////////////////////////////
#### Scenario 2:
sub foo { my %hash = (); .... %hash = .... # key/values populated by some API bar(\%hash, <other_args>); # <<<----- Is this better/best practi +ce compared to Scenario 1 ? } sub bar { my $hash_ref = shift; .... other function args are accessed here my @array = (); push (@array, $hash_ref); foreach my $i (.....) { .... %some_hash initialized here for each iteration of the for +-loop push (@array, \%some_hash); } zzz(\@array); # zzz() will do some read-only operations with this + array }

Replies are listed 'Best First'.
Re: Best practices for passing in function arguments?
by jcb (Parson) on Dec 09, 2015 at 22:22 UTC

    Remember that, in Perl, your subroutine arguments are an array. If bar will never take any other options, then there is no reason to pass in an arrayref unless you have other uses for the same array and need to avoid building it again, or if you really need for bar to change an array in its caller.

    Your scenarios are not quite equivalent. In scenario 1, calling bar changes the value of @arr in foo. In scenario 2, bar constructs its own array rather than changing one of foo's lexicals. In both of these, zzz must be careful not to change its argument, or it will change either @arr in foo (scenario 1) or @array in bar (scenario 2).

    Generally, this kind of close coupling is a fertile source of strange bugs and should be avoided unless performance is so critical that avoiding the overhead of building new arrays is needed or passing results back by modifying arguments is absolutely necessary.

    This pattern is common in C, but in Perl your return value can also be an array (or something very close to one), so modifying arguments is generally unnecessary and should be avoided (except of course for $self in object methods that specifically exist to mutate an object).

      Thanks for your feedback...
Re: Best practices for passing in function arguments?
by mr_ron (Chaplain) on Dec 09, 2015 at 20:25 UTC
    my $array_ref = {}; push(@$array_ref, {});
    The code above, which is part of your second example, gives an error because $array_ref = {} initializes your $array_ref to a hash ref which is not compatible as the first argument of push. It may be sort of symptomatic of your programming difficulties in that initializing $array_ref to a hash ref is confusing and just looks like code that is headed off in the wrong direction. I think your examples add more complication than needed and, for me, trying to simplify gives a result like:
    use strict; use warnings; sub foo { my %hash = (); .... %hash = .... # key/values populated by some API bar(\%hash); } sub bar { my $hash_ref = shift; my @arr_of_href = $hash_ref; foreach my $i (.....) { .... %some_hash initialized here for each iteration of the for + loop push (@arr_of_href, \%some_hash); } zzz(\@arr_of_href); # zzz() will do something with this array }
    Ron
      sorry about the incorrect usage; i've corrected the code snippet.
Re: Best practices for passing in function arguments?
by kcott (Archbishop) on Dec 09, 2015 at 22:09 UTC

    G'day andrewkl,

    Welcome to the Monastery.

    I think you're looking at this back-to-front.

    Write your subroutines such that they read the arguments they need. E.g.

    sub f { my ($AoH) = @_; for my $hashref (@$AoH) { # do something with $hashref } }

    Then call those subroutines with the appropriate arguments. E.g.

    ... # somewhere in your code f($AoH); ... # elsewhere in your code f([$hashref1, $hashref2]); ... # and at some other point f([\%hash]); ...

    As you can see from those examples, you can (often) create the argument list in situ.

    What you really want to avoid is subroutine definitions like this:

    sub g { my ($arrayref_containing_just_one_hashref) = @_; my $hashref = $arrayref_containing_just_one_hashref->[0]; # do something with $hashref }

    So, get the subroutine definition right, then call as needed. If that requires some complex code to create the argument list, so be it.

    — Ken

      Thank you for your feedback...
      I'm having a discussion with a colleague. She prefers scenario 1 whereas i think scenario 2 makes more sense.
Re: Best practices for passing in function arguments?
by GrandFather (Saint) on Dec 10, 2015 at 05:43 UTC

    When you write the code that calls the sub which version is easiest to understand when you or someone else reads the code in a month or more? Use that version. Almost always there is nothing else that matters.

    Premature optimization is the root of all job security
Re: Best practices for passing in function arguments?
by GotToBTru (Prior) on Dec 09, 2015 at 19:34 UTC

    The two alternatives are not equivalent, so choose whichever matches most closely to the useful parameters of your function.

    Dum Spiro Spero
      Hi,
      I guess my question is: Does it make sense to pass in an array that contains only one item (a ref to a hash). That array will always have only 1 item.

      Or is it better to directly pass in the hash array (Scenario 2)

      Thanks
      --Andrew

        Will the subroutine ever be expected to perform its task on a list of hashes? Then an array would make sense. Otherwise it seems a needless complication. Which is repeating what I said before. It's your subroutine; YOU figure out how you want to use it.

        Dum Spiro Spero

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1149817]
Front-paged by GotToBTru
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2024-04-26 06:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found