http://www.perlmonks.org?node_id=1187342

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

I am currently trying to pass a hash by reference to a subroutine. The hash is generated by the following query :

my $existing_users = $dbh->selectall_hashref("SELECT `UserName`, ` +LastAccessDate`, `Ignore` FROM $status_database.`Status`",1);

and prints out the following

'user1' => { 'UserName' => 'user1', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, 'user2' => { 'UserName' => 'user2', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' },

This wasn't a problem when I was using the hash globally but now I am trying to pass it to subroutines to organize the code a little better. I am sure this is something simple that I am just over looking. Doing the following simply prints out a number

send_to_sub(%{$existing_users}); sub send_to_sub{ my $existing_users = @_; print Dumper(\$existing_users); exit; }

Help would be appreciated

Replies are listed 'Best First'.
Re: Passing a hash byreference to a subroutine
by Discipulus (Canon) on Apr 06, 2017 at 20:18 UTC
    Hello edimusrex

    You are not passing it by reference: you are just passing the hash.

    What happens is that @_ in the sub flatten out the hash so each keys and values go into the @_ array and you assign it to a scalar $existing_users

    You pass by reference.. passing a reference: process_users(\%results) or process_users($results_reference) and inside the sub you just grab the first argument arrived in (the flattener) @_ and you know it is a reference, so:

    sub process_users( my $result_ref = shift; # dereference it if needed foreach my $key ( %$result_ref ){ ... )

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Passing a hash byreference to a subroutine
by Anonymous Monk on Apr 06, 2017 at 20:14 UTC
    Treat the ref like a normal scalar, no need to deref. Also it's my ($existing_users) = @_; (parens on the left for list context) or my $existing_users = shift;. See also perlreftut and perlref.

    use warnings; use strict; use Data::Dumper; my $existing_users = { 'user1' => { 'UserName' => 'user1', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, 'user2' => { 'UserName' => 'user2', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, }; send_to_sub($existing_users); sub send_to_sub { my ($existing_users) = @_; print Dumper($existing_users); }

      Ahh, I knew it would be something simple. Thank you

Re: Passing a hash byreference to a subroutine
by thanos1983 (Parson) on Apr 07, 2017 at 08:42 UTC

    Hello edimusrex,

    Well I think you should read this articles why you should pass a ref instead of a hash (Subroutines: Returning a hash vs. hash reference).

    After that I think you should read from the Perl CookBook (10.5. Passing Arrays and Hashes by Reference, 2.7.2 Passing References).

    Having said that you can pass the hash ref from your example in 3 different ways.

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper qw(Dumper); my $existing_users = { 'user1' => { 'UserName' => 'user1', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, 'user2' => { 'UserName' => 'user2', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, }; print Dumper send_to_sub($existing_users); print Dumper send_to_sub_2(\%{$existing_users}); print Dumper send_to_sub_3(\%$existing_users); sub send_to_sub { return @_; } sub send_to_sub_2 { return @_; } sub send_to_sub_3 { return @_; } __END__ $ perl test.pl $VAR1 = { 'user1' => { 'UserName' => 'user1', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, 'user2' => { 'UserName' => 'user2', 'LastAccessDate' => '0000-00-00', 'Ignore' => 'N' } }; $VAR1 = { 'user1' => { 'UserName' => 'user1', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, 'user2' => { 'UserName' => 'user2', 'LastAccessDate' => '0000-00-00', 'Ignore' => 'N' } }; $VAR1 = { 'user1' => { 'UserName' => 'user1', 'Ignore' => 'N', 'LastAccessDate' => '0000-00-00' }, 'user2' => { 'UserName' => 'user2', 'LastAccessDate' => '0000-00-00', 'Ignore' => 'N' } };

    As you can tell all subroutines return the same result. just different way of defining it.

    Update: I think this will also be useful for reading What does my ($data) = @_ mean?.

    Hope this helps.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Passing a hash byreference to a subroutine
by karthiknix (Sexton) on Apr 07, 2017 at 09:55 UTC

    referencing and dereferencing in Perl is used for passing data structures to subroutines. for examples @example is an array to pass it to subroutine

    @examples = ('perl', 'linux'); $reference_of_example = \@examples; #referencing your_sub($ref_example); sub your_sub { $ref = @_; print Dumper(@$ref); #@$ref is dereferencing array. }
      $ref = @_;

      Sorry, but that's not correct, it suffers from the same problem as the OP: it puts the array @_ into scalar context, meaning that $ref will hold the number of elements in @_, instead of its first element as intended. You'd need to write my ($ref) = @_;, as the parentheses on the left side place the right side into list context, and this will cause $ref to be assigned the first element of the array (and the rest of the elements to be ignored in this case).

      Also, this code won't work under strict (also note $reference_of_example vs. $ref_example). When posting code examples, please make sure to test them under strict and warnings.

      Hello karthiknix,

      Sample of your code using strict and warnings as haukex correctly pointed out.

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper qw(Dumper); my @examples = ('perl', 'linux'); my $reference_of_example = \@examples; #referencing print Dumper your_sub($reference_of_example); # prints $VAR1 = 1; print Dumper my_sub($reference_of_example); print Dumper my_solution($reference_of_example); print Dumper haukex_solution($reference_of_example); sub your_sub { my $ref = @_; return $ref; } sub my_sub { return @_; } sub my_solution { my $ref = shift @_; return $ref; # or return shift @_; } sub haukex_solution { my ($ref) = @_; return $ref; } __END__ $ perl test.pl $VAR1 = 1; $VAR1 = [ 'perl', 'linux' ]; $VAR1 = [ 'perl', 'linux' ]; $VAR1 = [ 'perl', 'linux' ];

      Update: Adding haukex solution.

      Hope this helps.

      Seeking for Perl wisdom...on the process of learning...not there...yet!