in reply to Re^6: Why is my code assigning the last-retrieved value to all elements in my hash?
in thread Why is my code assigning the last-retrieved value to all elements in my hash?

Look in perlref under "symbolic references" for the official scoop, but here's a brief tutorial.

The values in a hash are all scalars. You cannot store a hash in a hash. $h{key} is always a simple scalar value. A reference, however, is also a scalar, so you can store a reference to a hash in a hash.

When you say $h{key}{subkey}, the $h{key} in that expression has to be a reference to a hash. If it turns out that it's a reference to an array, for example, you'll get an error.

When you set $b{$bid} = 'foo' and then say $b{$bid}{'blah'} = 'hahaha', that treats $b{$bid} as a reference. It's a reference to a hash named %foo because $b{$bid} has the value "foo".

So, when you went from using "1" to using "ok", you went from putting everything in %1 to putting everything in %ok. You have the same problem by a different name.

If, as you write in Re^7: Why is my code assigning the last-retrieved value to all elements in my hash?, you set each value to a different string, it "works" because those "references" all go to different hashes.

$b{$bid} = "The Diamond Age"; # $b{$bid}{foo} uses %{"The Diamond Age"} $b{$bid} = "Snow Crash"; # $b{$bid}{foo} uses %{"Snow Crash"} $b{$bid} = "b"; # $b{$bid}{foo} pollutes %b directly!

What I've written about mostly so far is just symbolic references. There's another kind, hard references, that don't go around mucking up other variables, because they don't refer to other variables.

$b{$bid} = {};

That creates a hard reference to an anonymous hash. You can then use $b{$bid} to refer to the (anonymous) hash, and it won't destroy other variables willy nilly.

I hope this clears up what's going on with your code.

I've suggested several times that you use strict. I suggest this because it prevents you from using symbolic references. Any attempt to use a string as a reference will cause a fatal error. It also forces you to use my to declare your variables (or refer to them explicitly as package variables), which is another good thing.

There's one other misconception you seem to have that I'd like to clear up. You can't have a $b{foo}{bar} and have $b{foo} set to some unrelated value (such as 1). If there is a $b{foo}{bar}, then $b{foo} must somehow be a reference to a hash where you access ->{bar}. In your original code, that "reference" was "1", treated as a symbolic reference to %1. In the code I suggested, it's a hard reference to an anonymous hash that gets printed as 'HASH(0x8529f88)'.

Replies are listed 'Best First'.
Re^8: Why is my code assigning the last-retrieved value to all elements in my hash?
by punch_card_don (Curate) on Jul 09, 2008 at 22:32 UTC
    Thanks a heap for taking time to deal with this completely and in detail.

    I do believe that the truly salient point is this:

    There's one other misconception you seem to have that I'd like to clear up. You can't have a $b{foo}{bar} and have $b{foo} set to some unrelated value (such as 1). If there is a $b{foo}{bar}, then $b{foo} must somehow be a reference to a hash where you access ->{bar}. In your original code, that "reference" was "1", treated as a symbolic reference to %1. In the code I suggested, it's a hard reference to an anonymous hash that gets printed as 'HASH(0x8529f88)'.

    This appears to be the real root of the problem. I started with a one-dimensional hash, then extended it to two dimensions. $booklist_1{$book_id} therefore becomes a reference to a hash and I can no longer use it the way I was trying to.

    On this basis, I changed it to

    while ($book_id = $sth->fetchrow_array()) { $booklist_1{$book_id}{'book_id'} = 1; }
    and that works perfectly.



    Time flies like an arrow. Fruit flies like a banana.

      Unless there's some reason for wanting '1', I'd put the actual book ID in the 'book_id' slot of that hash.

      while (($book_id) = $sth->fetchrow_array()) { $booklist_1{$book_id}{'book_id'} = $book_id; }

      Unless you have a book ID of '0', it will still be true in boolean tests, and it will be less confusing to future programmers.

        Getting too squished on my screen - see bottom of thread for my conclusion in the light of the next day....




        Time flies like an arrow. Fruit flies like a banana.