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?