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

I want to be able to tie a scalar that's a hash element, where the hash itself is already tied. Is this not supported? I searched some and didn't find anything ... Here's some sample code that shows it doesn't work. The actual ties I'd use would be different but I want to get the general case working first. Here's the code. If I comment out the hash tie, the scalar tie works. I'm running Perl 5.6.1 on Solaris.
#!/usr/local/bin/perl use strict; use Tie::IxHash; use Tie::Scalar::Timeout; my %hash; tie %hash, "Tie::IxHash"; tie $hash{TIMED}, "Tie::Scalar::Timeout", EXPIRES => '+2s'; print "hash tie = ", tied(%hash), "\n"; print "TIMED tie = ", tied($hash{TIMED}), "\n";

Replies are listed 'Best First'.
Re: tying tied hash scalars
by fglock (Vicar) on Dec 02, 2002 at 19:07 UTC

    This one seems to work (it hashes a reference):

    use strict; use Tie::IxHash; use Tie::Scalar::Timeout; my %hash; tie %hash, "Tie::IxHash"; tie ${$hash{TIMED}}, "Tie::Scalar::Timeout", EXPIRES => '+2s'; print "hash tie = ", tied(%hash), "\n"; print "TIMED tie = ", tied(${$hash{TIMED}}), "\n";

    Output:

    hash tie = Tie::IxHash=ARRAY(0x80f8240) TIMED tie = Tie::Scalar::Timeout=HASH(0x81038e4)
      Yes, that works for me too. Problem is I now have to change all existing hash accesses to use the reference. Part of what I'm trying to do is alter the underlying behavior of a widely used hash, where the hash elements are already assumed to be tied themselves. I don't really want to change all that code. The idea was to tie the hash where it's created and leave the rest of the code alone.
(bbfu) (proxy object) Re: tying tied hash scalars
by bbfu (Curate) on Dec 02, 2002 at 21:36 UTC

    The best way I can think of (as in, requiring the least amount of existing codebase changes) is to create a "proxy object". In other words, tie the original hash to your own class which looks for the key you want to have tied separately and handles it specially.

    #!/usr/bin/perl -l use warnings; package Tie::MyHash; use Tie::Hash; @ISA = ('Tie::StdHash'); use Tie::IxHash; use Tie::Scalar::Timeout; sub TIEHASH { my $class = shift; my $hash = {}; tie %$hash, 'Tie::IxHash'; tie ${$hash->{'special'}}, 'Tie::Scalar::Timeout', EXPIRES => '+ +2s'; return bless $hash, $class; } sub FETCH { my ($this, $key) = @_; if($key eq 'special') { print tied(${$this->{'special'}}) if $key eq 'special'; return ${$this->{'special'}}; } else { print tied(%$this); return $this->{$key}; } } sub STORE { my ($this, $key, $value) = @_; return ${$this->{'special'}} = $value if($key eq 'special'); return $this->{$key} = $value; } sub AUTOLOAD { my $this = shift; my $sub = $AUTOLOAD; $sub =~ s/.*:://; tied(%$this)->$sub(@_); } # Tie::IxHash doesn't have a DESTROY method, so we need one sub DESTROY {} package main; tie my %hash, 'Tie::MyHash'; $hash{'mundane'} = 'foo'; $hash{'special'} = 'bar'; print $hash{'mundane'}; print $hash{'special'}; print "Keys: ", join(", ", tied(%hash)->Keys(0, 1)); sleep 3; print $hash{'special'} || 'undef';

    Update: Hrm. I just realized that the "special" key will not be considered part of the Tie::IxHash at all, for ordering purposes and such, so this isn't really a good solution either. I'll have to think about that...

    Update2: It was straight-forward to change it so that the "special" key was stored in the Tie::IxHash. Updated the code accordingly.

    bbfu
    Black flowers blossum
    Fearless on my breath

      I am using my own ties and I tried several kinds of trickery in there. No luck.

      It turns out, for this particual problem, I don't need this. I reanalyzed the design and found I was anticipating a need that will never really exist. But I'd still like to know the general approach here and what Perl is supposed to support. I like using ties but I've been caught before assuming I can do too much with them.

      Somewhat related: For another package I'm considering, I'd also like to be able to tie a file handle more than once; i.e., provide multiple file handle filters without anyone knowing. The only approach I can see there is to somehow maintain a list of ties ... If anyone's done anything here I'd like to hear about your approach.

Re: tying tied hash scalars
by John M. Dlugosz (Monsignor) on Dec 02, 2002 at 22:53 UTC
    I have an idea you might look into: perhaps the hash implementation behind the tied hash is returning ordinary scalar values rather than references to magic objects? For example, if your FETCH function returned a computed value, or something like 0+%internal{key}, then it would lose the magic from what you stored.

Re: tying tied hash scalars
by fglock (Vicar) on Dec 03, 2002 at 13:13 UTC

    It might be more difficult than I thought. I found this in http://archive.develooper.com/perl6-internals@perl.org/msg11133.html

    In perl5, one could only tie a hash..not a hash of arrays of hashes as a single object. To do this, you needed to have your tied hash return special tied arrays, etc. This is rather complex code to write, and rather slow, due to the generation and destructuin of all sorts of temporary objects. Damian's Regex::Common did this, but I don't know of any others. ... more