in reply to Missing something with regards to references

Your code is pretty close, but I'm afraid you need another level of referencing to deal with autovivifying. I'll try to explain why... Consider when you have an empty $DATA{3}{h} and call put_element($DATA{3}, 'h', 'i', "worked"). Then your code eventually does: That last line autovififies the undef in $current to a fresh anonymous hashref, fetches the key 'i' from the new anonymous hash (which returns undef), and sets $current to this undef... But overwriting the value of $current cleans up the anonymous hash that was just created. It's lost forever. Whoops!

Instead of this, you need to keep another level of references. Now instead of trying to keep the values of $DATA{3}, $DATA{3}{h}, $DATA{3}{h}{i} (which are copied, so don't do the right thing if the hash key doesn't exist), we have to keep references to those slots of the hashes. This way the new hashes can be autovivified in the appropriate slot, and not into your temporary variable.

You also need to use $_[0] instead of shift if the first argument has a hash dereference that may be autovifified (since shift makes a copy, but $_[0] is an alias to the first arg, not a copy).

sub put_element { my $current = \ $_[0]; shift; my $value = pop; $current = \ $$current->{ +shift } while @_; $$current = $value; } use Data::Dumper; my %DATA; put_element( $DATA{3}, 'h', 'i', "Worked" ); ## $DATA{3} autovifified + too put_element( $DATA{3}, 'b', 'y', 'e' ); ## $DATA{3} exists print Dumper \%DATA;
Yes, the autovivification makes this a very sticky situation. But if you can understand this, you are in very good shape with your understanding of references.

blokhead

Replies are listed 'Best First'.
Re^2: Missing something with regards to references
by scottb (Scribe) on Nov 01, 2004 at 23:27 UTC
    Thank you for the explination.

    It sort of make sense to me, but this is entirely new territory for me. I'd had a hunch at one time that the undef keys beneath the one I wanted would be a problem, but I couldn't quite wrap myself around what could be done about it. Using the reference rather than copies of values sort of makes sense too, but I think it needs time to sink in. I think the part about using $_[0] instead of shift makes the least sense to me... since I am always pathing through a reference, I apparently need to make a reference to the reference?

    Anyway, thank you. This is very helpful.

      since I am always pathing through a reference, I apparently need to make a reference to the reference?

      \$_[0] is not needed if the given (first) key is already a hashref. E.g.:

      my %DATA = (3 => {}); put_element($DATA{3}, ...);

      But it is needed if the key doesn't exist yet:

      my %DATA = (3 => {}); put_element($DATA{42}, ...);

      "But why doesn't my $current = \shift work? Why do I have to use my $current = \$_[0]?" Answer: If the key already exists and its value is a hashref, both possibilities work. But if the key does not exist, we have to make sure, that we really get a reference to the entry of %DATA, not the value of the non-existing entry.

      sub test1 { my $val = shift; $val = 5; } sub test2 { $_[0] = 5; } my ($a, $b) = (3, 3); test1($a); # $a continues to be 3. test2($b); # $b is 5 now.

      But I could have missed something, too.