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

This one surprised and stumped me. I found it chasing down a bug and boiled it down to the test case below. Basically, if I tie a hash then pass references to elements of that tied hash to sub's, those references appear in the sub as different values. Not always -- it depends on where in the arg list the reference is. Without the tie, it behaves as expected. I've tried several ties, so it's not specific to Tie::IxHash. This is Perl 5.6.1.

use strict; use Tie::IxHash; my $h = {}; tie %$h, "Tie::IxHash"; my $a; $h->{FOO} = 'foo'; print "reference to a = ", \$a, "\n"; print "reference to h->{FOO} = ", \$h->{FOO}, "\n"; show_refs(\$a, \$h->{FOO}); print "reverse order ...\n"; show_refs(\$h->{FOO}, \$a); sub show_refs { my $ref; foreach $ref (@_) { print "in show_refs, ref = $ref\n"; } }
produces ...
reference to a = SCALAR(0x102d4c) reference to h->{FOO} = SCALAR(0x13bdb8) in show_refs, ref = SCALAR(0x102d4c) in show_refs, ref = SCALAR(0x13bdd0) reverse order ... in show_refs, ref = SCALAR(0x13bdb8) in show_refs, ref = SCALAR(0x102d4c)
The first call has the reference to hash element $h->{FOO} as a different value than it is outside the sub; the second ('reverse order') has it the same.

Any idea what's going on here? I'd expect a reference to $h->{FOO} to be the same as what it is when I first check it -- not change when passed to a sub. FYI, I've also noticed that references to elements of tied hashes are the same for all elements after the tie, although this does not seem to affect the ability to dereference them later. tie magic I assume ...

Replies are listed 'Best First'.
Re: references to elements of tied hashes
by broquaint (Abbot) on Feb 05, 2003 at 12:03 UTC
    Any idea what's going on here? I'd expect a reference to $h->{FOO} to be the same as what it is when I first check it -- not change when passed to a sub
    This behaviour is due to the fact that while tied hashes behave very much like real hashes, internally they're very different (I've had trouble with this, see. lvalue trickery). When you retrieve a value from a tied hash you get back a new value every time even if you are accessing the same value in the hash e.g
    { package MyTH; use Tie::Hash; @ISA = qw( Tie::StdHash ); sub FETCH { return $_[0]->{$_[1]} } } use Devel::Peek; tie my %h, "MyTH"; $h{foo} = 1; Dump($h{foo}) for 1 .. 3; __output__ SV = PVMG(0x811a810) at 0x811f4a4 REFCNT = 1 FLAGS = (TEMP,GMG,SMG,RMG) IV = 0 NV = 0 PV = 0 MAGIC = 0x8103ab8 ... SV = PVMG(0x811a810) at 0x811f4a4 REFCNT = 1 FLAGS = (TEMP,GMG,SMG,RMG) IV = 0 NV = 0 PV = 0 MAGIC = 0x8104480 ... SV = PVMG(0x811a810) at 0x811f4a4 REFCNT = 1 FLAGS = (TEMP,GMG,SMG,RMG) IV = 0 NV = 0 PV = 0 MAGIC = 0x8104480 ...
    There a temporary value is created each time, but the value is always the same thing. Now if you create a reference you also get a temporary value, and stringified it will always change. What you're seeing in your code is that temporary reference being created each time and therefore a different stringification. So as you can see much 'magic' is going on behind the scenes of tied variables.
    HTH

    _________
    broquaint

Re: references to elements of tied hashes
by steves (Curate) on Feb 05, 2003 at 21:07 UTC

    This is good. Thanks.

    Maybe you can answer this one: The bug that started me down this path is something I mentioned having problems with before but in a different area. I can't tie elements of the tied hash. I think someone mentioned this as not possible. The reference issue came up in the course of tracking that down because when tying the reference, the tie works. I can only assume it's tying something I can no longer refer to. Test code using a hash-based scalar tie for the hash elements that upper cases them. Note that I also tried Tie::StdScalar with the same results (except that the tie did nothing).

    package TieTest; sub TIESCALAR { return bless({}, __PACKAGE__) } sub STORE { @_[0]->{VALUE} = uc(@_[1]) } sub FETCH { @_[0]->{VALUE} } use strict; use Tie::IxHash; my $h = {}; my $a; tie %$h, "Tie::IxHash"; tie $h->{FOO}, "TieTest"; $h->{FOO} = 'foo'; tie $a, "TieTest"; $a = 'bar'; print "After scalar tie ...\n"; print "\$h->{FOO} = $h->{FOO}\n"; print "\$a = $a\n"; print "\$a tied? ", tied($a), "\n"; print "h->{FOO} tied? ", tied($h->{FOO}), "\n"; tie_ref(\$a); tie_ref(\$h->{FOO}); $a = 'bar2'; $h->{FOO} = 'foo2'; print "After reference tie ...\n"; print "\$h->{FOO} = $h->{FOO}\n"; print "\$a = $a\n"; print "\$a tied? ", tied($a), "\n"; print "h->{FOO} tied? ", tied($h->{FOO}), "\n"; sub tie_ref { my $ref = shift; my $tie; $tie = tie $$ref, "TieTest"; print "tie for reference $ref = $tie\n"; }
    produces:
    After scalar tie ... $h->{FOO} = foo $a = BAR $a tied? TieTest=HASH(0x13c8dc) h->{FOO} tied? tie for reference SCALAR(0x102efc) = TieTest=HASH(0x13c81c) tie for reference SCALAR(0x13c8d0) = TieTest=HASH(0x13c840) After reference tie ... $h->{FOO} = foo2 $a = BAR2 $a tied? TieTest=HASH(0x13c81c) h->{FOO} tied?

    I love the abstraction ties offer but I find that all the nuances of using them are not well documented. Are there docs I'm missing that discuss ties in more detail?

    The good news is that all this tracking helped me finally understand some inconsistent behavior. 8-)

      So, it's a year and a half later and this gets me again in a way I can't solve: I have a self-referential hash. I use WeakRef to weaken the hash elements to avoid leaking/growing programs. But if I tie the hash I can't find any way to weaken the tied references. Any ideas besides shooting me in the head?

        Question related to this: Are stringified references used as hash keys unique? That is, if I only ever use them to look hashed values for given references up, do I need to use something like Tie::RefHash? I've gotten into the habit of using Tie::HashRef whenever I use references as hash keys. I realize now that in many cases I'm never trying to dereference the keys -- only take a reference and find its hashed value. So in the case above, I probably don't need a tie and I can therefore weaken the self referential reference I'm using as a key. The hash in question is always hashing references to bless'ed hashes of the same object (package) type.