Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

More efficient ways to pass values to a sub routine

by Anonymous Monk
on Jan 31, 2017 at 19:33 UTC ( [id://1180716]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks!

I have an issue where I am passing some values to a sub routine and I can only see the values been passed if they are passed like it is in my sample code  sub send_1 - I just can not see to understand why it wont work on both. Any thoughts?
Here is a code to show how I am passing to the subs.
... send_1( name => $name, filehandle => $pic, id => 'test' ); send_2( { name => $name, filehandle => $pic, id => 'test'} ); sub send_1 { my (%args) = @_; my $name = $args{ name } || ''; my $filehandle = $args{ filehandle } || ''; my $id = $args{ id } || ''; } sub send_2 { my $name = $_[0] || ''; my $filehandle = $_[1] || ''; my $id = $_[2] || ''; } ...

Replies are listed 'Best First'.
Re: More efficient ways to pass values to a sub routine
by haukex (Archbishop) on Jan 31, 2017 at 19:46 UTC

    Hi Anonymous,

    send_1 is a good example of passing named parameters to a sub with a hash. (Update: Technically, what is happening is that the subroutine is passed a flat list of key+value pairs, since using the => operator doesn't automatically make something a hash. However, once you say my (%args) = @_;, that flat list of key+value pairs is stored in a hash.)

    However, in send_2, in the call of the sub (send_2( { name => ... } )) what you are passing the sub is a reference to an anonymous hash, whereas the implementation of sub send_2 is expecting a flat list of positional parameters. The correct way to call the sub send_2 in your example code would be:

    send_2( $name, $pic, 'test' );

    If instead you wanted to implement arguments passed in as a hash reference, you'd need to rewrite sub send_2 like this (untested):

    sub send_2 { my ($args) = @_; my $name = $args->{ name } || ''; my $filehandle = $args->{ filehandle } || ''; my $id = $args->{ id } || ''; }

    Update: See "Use Rule 2" in perlreftut for an explanation of the $args->{...} syntax. Note that it could also be written $$args{...}.

    Hope this helps,
    -- Hauke D

Re: More efficient ways to pass values to a sub routine
by toolic (Bishop) on Jan 31, 2017 at 19:47 UTC
    You pass a reference to a hash to send_2. This ref is placed into the 1st element of @_ inside the sub. Here is one way to access the hash keys:
    sub send_2 { my $args = shift; my $name = $args->{name} || ''; }

Re: More efficient ways to pass values to a sub routine
by FreeBeerReekingMonk (Deacon) on Jan 31, 2017 at 19:55 UTC
    Perl auto-flattens these => to a comma, so instead of a single hash as parameter, it is converted automatically to an array of many parameters.

    You can avoid it, but it is clunky:

    use 5.010; sub send_3{ my ($h) = @_; # 'fix' if broken parameters unless(ref($h) eq 'HASH'){ my %X = @_; $h = \%X; } # set default values $h->{foo} //='default'; # iterate over parameters for my $key (keys %$h){ say "$key ~> $h->{$key}" } } send_3( {"foo"=>42, "bar"=>'code'}); send_3( "baz"=>11, "zab"=>'dong');

    Which yields:

    fbrm@monastery:~/CODE/PERL/monks$ perl x foo ~> 42 bar ~> code zab ~> dong foo ~> default baz ~> 11

    Note that starting from perl 5.10, you can use the "//=" operator to test if the variable is defined, and not just non-zero. (Imagine the call send_3(foo=>"0", bar=>"cool"), which using the above would yield "default cool", which might not be what you wanted. Using the //= operator it would yield "0 cool").

Re: More efficient ways to pass values to a sub routine
by Cristoforo (Curate) on Jan 31, 2017 at 23:42 UTC
    Here is a way to initialize defaults if a key/value are not passed to the sub. Forget where I saw this technique, possibly here.

    use Data::Dumper; sub send_2 { my %args = (name => 'default', filehandle => 'default', id => 'default', %{ +shift } ); print Dumper \%args; } send_2( {name => 'Tom', id => 'IT001'} ); send_2( {name => 'Mary', filehandle => 'ARGV', id => 'foo'} );
    Output is:
    $VAR1 = { 'filehandle' => 'default', 'name' => 'Tom', 'id' => 'IT001' }; $VAR1 = { 'filehandle' => 'ARGV', 'name' => 'Mary', 'id' => 'foo' };
    The sub assigns a default value (here 'default') which is overwritten if a value is passed to the sub when called.

    (You could have just as easily have a default == the empty string ('') or whatever you want as a default.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-04-18 05:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found