Dear Monks,
I am having a bit of a problem with the following code--I am creating a tied scalar on the fly from within the FETCH method of a tied hash, and trying to return that tied scalar. I can get the tied scalar to be returned with a bit of cleverness, but then the tied scalar appears to no longer be tied. Even though ref tells me that it is a 'Tie::Scalar', but tied returns undef meaning it's not tied. For further wackiness, I can manually call $tied_scalar->FETCH on the tied scalar and it works, but just $tied_scalar does not automatically call fetch. Would anyone happen to know what is going on here and how I can keep the tied scalar from untying itself?
The general idea I'm trying to get working:
tie our %conf, 'My::Hash';
# $dir is a tied Tie::Scalar
our $dir = $conf{'dir'};
print $dir, $/;
# prints /home/foo for example
# using tie magic, storing a value in $dir also updates
# 'dir' in %conf
$dir = '/somewhere/else';
$dir = $conf{'dir'};
print $dir, $/;
# now prints /somewhere/else
I want %conf to be a general wrapper that can be treated like a hash, so tie seems like the way to go. I also want to fetch values from %conf, store them in scalars, and then when those scalars are changed I would like transparent changes to occur back in the tied hash. Kind of confusing, I know. But I need it this way, so lets just suspend alternative designs and look at it as a pure exercise in Perl.
package My::Hash;
use base 'Tie::Hash';
our %hash = ('dir' => '/home/foo');
sub TIEHASH {
return bless \%hash, __PACKAGE__;
}
sub STORE {
my ($self, $key, $val) = @_;
$self->{$key} = $val;
}
sub FETCH {
my ($self, $key) = @_;
my $val = $self->{$key};
tie my $tied_scalar, 'My::Scalar', $key, $val;
return $tied_scalar;
}
1;
package My::Scalar;
use base 'Tie::Scalar';
sub TIESCALAR {
my ($self, $key, $val) = @_;
return bless {'value' => $val,
'key' => $key ,
'fetched' => 0
}, __PACKAGE__;
}
sub STORE {
my $self = shift;
my $newval = shift;
my $key = $self->{'key'};
My::Hash::hash{$key} = $self->{'value'} = $newval;
}
sub FETCH {
my $self = shift;
# this cleverness is done so that Tie::Hash FETCH does not
# call Tie::Scalar FETCH when it tries to return the tied
# scalar.
if ($self->{'fetched'}) {
return $self->{'value'};
}else{
$self->{'fetched'} = 1;
return $self;
}
}
1;
Now using the above code something unexpected happens:
tie our %conf, 'My::Hash';
our $dir = $conf{'dir'};
print ref $dir, $/;
# prints 'My::Scalar';
print tied $dir ? 1 : 0;
# prints 0
print $dir, $/;
# prints 'My::Scalar=HASH(0x820f268)'
print $dir->FETCH
# prints '/home/foo';
# attempts to call $dir->STORE give lvalue errors
#
# why is $dir untied now yet I can still call tied methods
# on it?
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.