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.
}
- 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.
CodePudding user response:
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
is populated with everything in @_
, as
%hash = (\%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?)
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
. Likeforeach 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.
CodePudding user response:
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("\n\t",@{$href_0->{$_}}) for (keys %$href_0);
say 'Hash 1';
say '-' x 45;
say "\t$_ => " . join("\n\t",@{$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