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

G'day. I feel terribly stupid today. Been out of touch with my more complicated Perl project for half a year, and now I cannot wrap my brain around hash and array references anymore.

I want to be able to recursively copy a hash of arrays of scalars (manually, so I can make adjustments on certain nodes). But I fail in creating writeable references to all types (hash, array, scalar) to pass to my recursion routine. A short example with my error looks like this:

my %testHash; # initialize hash my $hashRef = \%testHash; # get a reference to that # get a reference to an element 'a' inside the hash (that does not +yet exist) my $destref = \${$hashRef->{'a'}}; # <- problematic line # assign a value to the hash element 'a' $destref = "value"; # verify the result print $hashRef->{'a'} . "\n"; # outputs "SCALAR(0xaddress)"

In essence, I do not even know whether the "problematic line" is able to create a valid reference, because element 'a' does not exist at the time. How do I get a $destref that I could also pass to a function, and when modifying it's value, accomplish a change of $hashRef->{'a'}?

Thanks in advance for any help. I have done this before and can't get my head around my own code at the moment. I hope I am making sense :/

Replies are listed 'Best First'.
Re: recursively building a hash of arrays of scalars
by choroba (Cardinal) on Sep 30, 2015 at 16:16 UTC
    my %testHash; my $hashRef = \%testHash; my $destref = \$hashRef->{'a'}; # Just a reference to the value, no de +reference involved. $$destref = "value"; # Assign to the dereference. print $hashRef->{'a'} . "\n";
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Thank you very much! I am glad I reduced my initial problem to a minimalistic version. With your (all posters) responses, and a little bit of experimenting, I solved my problem and can now create any combination of hash, array and scalars solely working with references:

      #!/usr/bin/perl use strict; use warnings; use Data::Dump; my %testHash; # initialize hash my $hashRef = \%testHash; # get a reference to that $hashRef->{'a'} = "Hello World!"; my $destref = \$hashRef->{'b'}; # Just a reference to the value, no de +reference involved. # initialize hash element as empty array $$destref = []; # NOTE: this line is not necessary # assign a value to the hash element 'a' @{$$destref}[0] = "How"; # Assign to the dereference. @{$$destref}[1] = "are"; # Assign to the dereference. # initialize array element as empty hash @{$$destref}[2] = { }; # NOTE: this line *is* necessary @{$$destref}[2]->{'c'} = "you"; # assign values to hash @{$$destref}[2]->{'d'} = "today?"; # dd \%testHash; # Output: # { # a => "Hello World!", # b => ["How", "are", { c => "you", d => "today?" }], # }
        Line 22 is not necessary if you use the more common syntax:
        my %testHash; my $hashRef = \%testHash; $hashRef->{a} = "Hello World!"; my $destref = \$hashRef->{b}; # assign a value to the hash element 'a' $$destref->[0] = 'How'; $$destref->[1] = 'are'; $$destref->[2]{'c'} = "you"; $$destref->[2]{'d'} = "today?";
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: recursively building a hash of arrays of scalars
by Athanasius (Cardinal) on Sep 30, 2015 at 16:39 UTC

    Hello aral,

    I do not even know whether the "problematic line" is able to create a valid reference, because element 'a' does not exist at the time.

    It is able to do this, as you can see by dumping the contents of %testHash immediately afterwards:

    #! perl use strict; use warnings; use Data::Dump; my %testHash; # initialize hash my $hashRef = \%testHash; # get a reference to that # get a reference to an element 'a' inside the hash (that does not yet + exist) my $destref = \${$hashRef->{'a'}}; # <- problematic line dd \%testHash;

    Output:

    2:28 >perl 1389_SoPW.pl { a => \undef } 2:28 >

    This occurs because of autovivification, an important feature of Perl. See the tutorial “Autovivification: What is it and why do I care?” by Uri Guttman.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: recursively building a hash of arrays of scalars
by Laurent_R (Canon) on Sep 30, 2015 at 17:13 UTC
    If I understand correctly, you want to use $destref to modify your hash. Perhaps what you are looking for is illustrated in the following session under the debugger:
    DB<1> %testHash =(); DB<2> $hashRef = \%testHash; DB<3> $destref = \${$hashRef->{'a'}}; DB<4> x \%testHash; 0 HASH(0x302ee0c8) 'a' => SCALAR(0x302ee218) -> undef DB<5> $$destref = 42; DB<6> x \%testHash; 0 HASH(0x302ee0c8) 'a' => SCALAR(0x302ee218) -> 42
    As you can see, assigning 42 to $$destref does the trick. But is this what you are trying to do? Hum, probably not, because you have here one extra level of indirection that you probably don't want.

    So, maybe, you rather want something like this:

    DB<1> %testHash =(); DB<2> $destref = \$testHash{'a'} DB<3> x \%testHash; 0 HASH(0x302ee0c8) 'a' => undef DB<4> $$destref = 42; DB<5> x \%testHash; 0 HASH(0x302ee0c8) 'a' => 42
    My gut feeling (if I understood correctly) is that this is more probably what you are trying to do.