views:

536

answers:

4

I was asked to modify some existing code to add some additional functionality. I have searched on Google and cannot seem to find the answer. I have something to this effect...

%first_hash = gen_first_hash();
%second_hash = gen_second_hash();
do_stuff_with_hashes(%first_hash, %second_hash);

sub do_stuff_with_hashes
{
    my %first_hash = shift;
    my %second_hash = shift;

    # do stuff with the hashes
}

I am getting the following errors:

Odd number of elements in hash assignment at ./gen.pl line 85.
Odd number of elements in hash assignment at ./gen.pl line 86.
Use of uninitialized value in concatenation (.) or string at ./gen.pl line 124.
Use of uninitialized value in concatenation (.) or string at ./gen.pl line 143.

Line 85 and 86 are the first two lines in the sub routine and 124 and 143 are where I am accessing the hashes. When I look up those errors it seems to suggest that my hashes are uninitialized. However, I can verify that the hashes have values. Why am I getting these errors?

+8  A: 

The hashes are being collapsed into flat lists when you pass them into the function. So, when you shift off a value from the function's arguments, you're only getting one value. What you want to do is pass the hashes by reference.

do_stuff_with_hashes(\%first_hash, \%second_hash);

But then you have to work with the hashes as references.

my $first_hash  = shift;
my $second_hash = shift;
Mark Canlas
I see... That did the trick... Thanks alot!
predhme
+2  A: 

First off,

 do_stuff_with_hashes(%first_hash, %second_hash);

"streams" the hashes into a list, equivalent to:

 ( 'key1_1', 'value1', ... , 'key1_n', 'value1_n', 'key2_1', 'value2_1', ... )

and then you select one and only one of those items. So,

 my %first_hash = shift;

is like saying:

 my %first_hash = 'key1_1'; 
 # leaving ( 'value1', ... , 'key1_n', 'value1_n', 'key2_1', 'value2_1', ... )

You cannot have a hash like { 'key1' }, since 'key1' is mapping to nothing.

Axeman
Thanks for explaining what was going on behind the scenes.
predhme
+3  A: 

Hash references are the way to go, as the others have pointed out.

Providing another way to do this just for kicks...because who needs temp variables?

do_stuff_with_hashes( { gen_first_hash() }, { gen_second_hash() } );

Here you are just creating hash references on the fly (via the curly brackets around the function calls) to use in your do_stuff_with_hashes function. This is nothing special, the other methods are just as valid and probably more clear. This might help down the road if you see this activity in your travels as someone new to Perl.

Kyle Walsh
Great trick! Ill keep that around.
predhme
Happy to oblige. One thing to keep in mind if you stick around in Perl is that everyone will point out how "There's more than one way to do it". It's kind of a blessing and a curse )depending on your opinion of such things) in Perl programming. Have fun!
Kyle Walsh
+2  A: 

A bit late but,

As have been stated, you must pass references, not hashes.

do_stuff_with_hashes(\%first_hash, \%second_hash);

But if you need/want to use your hashes as so, you may dereference them imediatly.

sub do_stuff_with_hashes {
    my %first_hash = %{shift()};
    my %second_hash = %{shift()};
};
larelogio