skip to Main Content

We are trying to pass multiple hashes together with bunch of scalars as arguments to a subroutine. The problem is in multiple calls of this subroutine, ( and if we print the two hashes after we retrieved them inside the function), only one of them ( the first) is getting proper value. The second one is coming off as null. We tried bunch of things –

1 ) two separate hashes with different syntaxes from Stackoverflow/PerlMonks etc with pass on as reference.

&mySub(%hash0, %hash1, $var0, $var1, $var2);

sub mySub{
   my (%hash0, %hash1, $var0, $var1, $var2) = (@_);
}

OR

&mySub(%hash0, %hash1, $var0, $var1, $var2);

sub mySub{
   my %hash0 = %{$_[0]};
   my %hash1 = %{$_[1]};
   my $var0  = $[2]; my $var1 = $[3]; my $var3 = $[4];
}

2 ) Create array of two hashes and pass

my @joined_arr = (%hash0, %hash1);
&mySub (@joined_arr, $var0, $var1, $var2);

sub mySub{
   my (@joined_arr, $var0, $var1, $var2) = (@_);
   my %hash0 = %{joined_arr[0]};
   my %hash1 = %{joined_arr[1]};
   # rest of the variables.
}

4 ) Create hash of hashes and pass

my %joined_hash;
%joined_hash{"first_one"} = %hash0;
%joined_hash{"second_one"} = %hash1;
&mySub (%joined_hash, $var0, $var1, $var2);

sub mySub{
   my %joined_hash, %hash0, %hash1;
   %joined_hash = %{$_[0]};
   %hash0 = %joined_hash{"first_one"};
   %hash1 = %joined_arr{"second_one"};
   # rest of the variables.
}
  1. Try them in Perl 5.16 ( default distribution of CentOS 7) and hen in Perl 5.30.

Till this point, this hasn’t been a success. If anybody has an idea and like to share, it will be great help.


EDIT

Following the suggestion of @zdim and @Polar Bear, I have tried these things ->

Syntax for offloading @_ into scalars inside function ->

a)
my ($ref_to_hash0, $ref_to_hash1, $var0, $var1, $var2) = @_;

b)

$ref_to_hash0 = shift;
$ref_to_hash1 = shift;
$var0 = shift;
$var1 = shift;    
$var2 = shift;

I have also tried these 3 style of hash-reference to hash assignment.

a)
my %local_hash_shallow_copy = %$ref_to_hash0;

b)
my $local_hashref_deep_copy = dclone $ref_to_hash0;

c)
my %local_hash_shallow_copy = %{$ref_to_hash0};

It seems out of 9 iterations of this sub call, I am getting right hash inside the sub 2 times. At other times I simply get a pointer dumped –

$VAR1 = {
   'HASH(0x1e32cc8)' => undef
};

I am using Dumper to dump the hashes just Outside – right before the sub call, and just Inside – right after I transferred the value from ref to actual hash. This should avoid any silly mistake.

Either I might be doing a very basic mistake here or hit upon an uncanny issue. Am debugging it.

FYI.

2

Answers


  1. A function call in Perl passes a list of scalars as arguments, what you are correctly doing. The function receives a list of scalars in @_, which are aliases of those arguments.

    So with the call

    mySub(%hash0, %hash1, $var0, $var1, $var2);
    

    the function gets in @_ five scalars, the first two being the hash-references of interest.

    But now you assign those to a hash!

    sub mySub{
       my (%hash0, %hash1, $var0, $var1, $var2) = (@_);   # WRONG
    }
    

    So that %hash0 variable in the subroutine gets populated with everything in @_, like

    # MySub variable      # variables from the caller, (their aliases) passed in
    my %hash0         =   (%hash0 => %hash1, $var0 => $var1, $var2 => undef);
    

    since consecutive scalars are assigned as key-value pairs. The rest of the variables in the list, starting with %hash1, are also introduced as lexical symbols in that subroutine and are undef.

    And you should be getting a warning if the number of arguments is indeed odd. (There is use warnings; line on the top of your program, right?)

    Instead, need to assign elements of @_ to suitable scalars, for example like

    sub mySub{
       my ($ref_to_hash0, $ref_to_hash1, $var0, $var1, $var2) = @_;       
    }
    

    Now you have two options for how to work with this

    • Work directly with the reference(s), $ref_to_hash0. Like

      foreach my $key (keys %$ref_to_hash0) {
          $ref_to_hash0->{$key} ...
      }
      

      In short, this is

      • Efficient since you aren’t copying data

      • It may be inefficient since every access needs to dereference

      • It allows you to change data in the caller by writing to $ref_to_hash0

        $ref_to_hash0->{some_key} = 'value';  # changes data IN THE CALLER
        

        This may be convenient, or dangerous (as it can be done by a mistake)

    • Make a local copy of the caller’s data and work with that. Note that there may be a little catch with that, as you may need a deep copy

      use Storable qw(dclone);  # may be needed
      
      sub mySub{
          my ($ref_to_hash0, $refhash1, $var0, $var1, $var2) = @_;       
      
          # If the caller's %hash0 has no references for values just dereference
          # Tricky though -- what when the calling hash changes in the future?
          my %local_hash_shallow_copy = %$ref_to_hash0;
      
          # If the caller's %hash0 is a complex data structure, need a deep copy
          my $local_hashref_deep_copy = dclone $ref_to_hash0;
      
          # Changes to local hash/hashref do not affect data in the caller
      }
      

    There is generally no need for that leading & in front of the name in the question, omitted here, unless you mean to suppress its prototype in the call.

    Login or Signup to reply.
  2. You can not to pass hash or an array into subroutine, instead you pass hash reference or array reference (%hash or @array).

    In subroutine you should treat received argument as a reference. You can access data directly through reference $hashref->{key} or $arrayref->[index], or create a copy (more expensive on CPU cycles and memory) my %hash = %{$hashref} or my @array = @{$arrayref}.

    Please see demonstration sample code bellow.

    use strict;
    use warnings;
    use feature 'say';
    
    use Data::Dumper;
    
    my %hash_0 = ( data => [ 'it is snowing', 'this month', 'almost every day'] );
    my %hash_1 = ( data => [ 1, 2, 5, 7, 11 ] );
    my $var0 = 'The summer at it's end';
    my $var1 = 3356;
    my $var2 = 'Adorable child';
    
    my $agregate = { hash_0 => %hash_0, 
                     hash_1 => %hash_1, 
                     var0   => $var0, 
                     var1   => $var1,
                     var2   => $var2 
                };
                
    subHashes_1(%hash_0, %hash_1, $var0, $var1, $var2);
    say "n";
    subHashes_2(%hash_0, %hash_1, $var0, $var1, $var2);
    say "n";
    subHashes_3($agregate);
    say "n";
    subHashes_4(%hash_0, %hash_1, $var0, $var1, $var2);
    
    sub subHashes_1 {
        my($href_0, $href_1, $var0, $var1, $var2) = @_;
        
        say '--- subHashes_1 --------------';
        say 'Hash 0';
        say Dumper($href_0->{data});
        say 'Hash 1';
        say '-' x 45;
        say Dumper($href_1->{data});
        say 'Var0: ' . $var0;
        say 'Var1: ' . $var1;
        say 'Var2: ' . $var2;
    }
    
    sub subHashes_2 {
        my $href_0 = shift;
        my $href_1 = shift;
        my $var0   = shift;
        my $var1   = shift;
        my $var2   = shift;
    
        say '--- subHashes_2 --------------';
        say 'Hash 0';
        say Dumper($href_0->{data});
        say 'Hash 1';
        say '-' x 45;
        say Dumper($href_1->{data});
        say 'Var0: ' . $var0;
        say 'Var1: ' . $var1;
        say 'Var2: ' . $var2;
    }
    
    sub subHashes_3 {
        my $args = shift;
        
        my $href_0 = $args->{hash_0};
        my $href_1 = $args->{hash_1};
        my $var0   = $args->{var0};
        my $var1   = $args->{var1};
        my $var2   = $args->{var2};
        
        say '--- subHashes_3 --------------';
        say 'Hash 0';
        say Dumper($href_0->{data});
        say 'Hash 1';
        say '-' x 45;
        say Dumper($href_1->{data});
        say 'Var0: ' . $var0;
        say 'Var1: ' . $var1;
        say 'Var2: ' . $var2;
    }
    
    sub subHashes_4 {
        my $href_0 = shift;
        my $href_1 = shift;
        my $var0   = shift;
        my $var1   = shift;
        my $var2   = shift;
    
        say '--- subHashes_4 --------------';
        say 'Hash 0';
        say "t$_ => " . join("nt",@{$href_0->{$_}}) for (keys %$href_0);
        say 'Hash 1';
        say '-' x 45;
        say "t$_ => " . join("nt",@{$href_1->{$_}}) for (keys %$href_1);
        say 'Var0: ' . $var0;
        say 'Var1: ' . $var1;
        say 'Var2: ' . $var2;
    }
    

    Output

    --- subHashes_1 --------------
    Hash 0
    $VAR1 = [
              'it is snowing',
              'this month',
              'almost every day'
            ];
    
    Hash 1
    ---------------------------------------------
    $VAR1 = [
              1,
              2,
              5,
              7,
              11
            ];
    
    Var0: The summer at it's end
    Var1: 3356
    Var2: Adorable child
    
    
    --- subHashes_2 --------------
    Hash 0
    $VAR1 = [
              'it is snowing',
              'this month',
              'almost every day'
            ];
    
    Hash 1
    ---------------------------------------------
    $VAR1 = [
              1,
              2,
              5,
              7,
              11
            ];
    
    Var0: The summer at it's end
    Var1: 3356
    Var2: Adorable child
    
    
    --- subHashes_3 --------------
    Hash 0
    $VAR1 = [
              'it is snowing',
              'this month',
              'almost every day'
            ];
    
    Hash 1
    ---------------------------------------------
    $VAR1 = [
              1,
              2,
              5,
              7,
              11
            ];
    
    Var0: The summer at it's end
    Var1: 3356
    Var2: Adorable child
    
    
    --- subHashes_4 --------------
    Hash 0
            data => it is snowing
            this month
            almost every day
    Hash 1
    ---------------------------------------------
            data => 1
            2
            5
            7
            11
    Var0: The summer at it's end
    Var1: 3356
    Var2: Adorable child
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search