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

Hi Monks,

I'm trying to write a subroutine that adds a key-value pair to an array of hashes declared in the main program. I'd like to pass the subroutine a reference to a particular hash in the array (say the first one), and then access the added key-value pair back in the main program. Here's an example:
#!/usr/bin/perl use strict; use warnings; my @array_of_hashes; Add_key_and_value( $array_of_hashes[0], qw/ James Bond / ); print $array_of_hashes[0]{'James'}, "\n"; # Should print 'Bond'.
Now, it works fine if I define Add_key_and_value like that:
sub Add_key_and_value { $_[0]->{ $_[1] } = $_[2]; }
However, I'd rather define the subroutine like that:
sub Add_key_and_value { my( $ref, $key, $value ) = @_; $ref->{ $key } = $value; }
but this yields "use of uninitialized value in print...".

Could anyone explain to me what is wrong with the latter definition?

Thanks in advance.

Replies are listed 'Best First'.
Re: Passing a reference to an element in an array of hashes
by roubi (Hermit) on Mar 31, 2009 at 00:35 UTC
    In your first sub, $_[0] is an alias for $array_of_hashes[0], which gets auto-vivified, and therefore $array_of_hashes[0] too. In your second sub, $ref also gets vivified, but it has no relation to @array_of_hashes, which stays undef. Update: fixed typo in var name
Re: Passing a reference to an element in an array of hashes
by jethro (Monsignor) on Mar 31, 2009 at 00:30 UTC

    I don't know what you did in the first version, but I get a warning message there too. Could it be that you had warnings off in that version?

    To find such bugs it is often helpful to add a line like print ":$_[0]:$_[1]:$_[2]:\n"; before the problem line

    The reason is that your array (of hashes) is empty, $array_of_hashes[0] does not exist. If you add a line  push @array_of_hashes,{}; before the call of Add_key_and_value, the warning vanishes

    UPDATE: My observation that I got a warning message for the first version was wrong, the warning came from the print statement I added. Doh

Re: Passing a reference to an element in an array of hashes
by graff (Chancellor) on Mar 31, 2009 at 01:22 UTC
    Maybe you want to do it like this:
    my @array_of_hashes; Add_key_and_value( \@array_of_hashes, 0, qw/ James Bond / ); #... sub Add_key_and_value { my( $ref, $index, $key, $value ) = @_; $ref->[$index]{ $key } = $value; }
Re: Passing a reference to an element in an array of hashes
by NetWallah (Canon) on Mar 31, 2009 at 05:02 UTC
    Following up on what roubi(++) said, if you still want to do it your way, you need to maintain the aliasing of $_[0]. This code does what you expect:
    sub Add_key_and_value { our $ref; # so that "Strict" does not complain (use vars qw[$ref] + also works) local *ref = \$_[0]; # when "$ref" springs into existence, aliased +to $_[0] my (undef, $key, $value ) = @_; $ref->{ $key } = $value; }

         ..to maintain is to slowly feel your soul, sanity and sentience ebb away as you become one with the Evil.

Re: Passing a reference to an element in an array of hashes
by textual (Novice) on Mar 31, 2009 at 06:31 UTC
    I get it, thanks a lot for your replies.