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.
2
Answers
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†
the function gets in
@_
five scalars, the first two being the hash-references of interest.But now you assign those to a hash!
So that
%hash0
variable in the subroutine gets populated with everything in@_
, likesince 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 areundef
.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 likeNow you have two options for how to work with this
Work directly with the reference(s),
$ref_to_hash0
. LikeIn 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
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
† 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.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}
ormy @array = @{$arrayref}
.Please see demonstration sample code bellow.
Output