Let me be more explicit. If you change something from a simple accessor that you reach through the tie methods like $foo{'bar'} = 7 to a method call, you will have to either change that calling code to something like tied($foo)->set_bar(7) or else put a special case in the FETCH method so that it calls "set_bar()" if the key is "bar". This would break the abstraction in the former case or compicate the code in the latter.
UPDATE: as requested, an example, using your code.
Say we change the definitions of get/set_foo in MyThing to something like this:
sub set_foo {
my ($self, $newfoo) = @_;
$self->[1] = localtime(); # track last change
$self->[0] = $newfoo;
$self->_recalculate_bar();
}
sub get_foo {
$self->[2] = localtime(); # track last access
return $_[0]->[0];
}
After this change, the $clunker code using MyThing requires no changes at all. On the other hand, the tied HashAPI version, must change the accessing code from this:
$slick->{foo} = 'Some value';
print $slick->{foo}, "\n";
to this:
$slick->set_foo('Some value');
print $slick->get_foo(), "\n";
You could avoid needing this change by changing the FETCH and STORE, like this:
sub STORE {
my ($self, $key, $val) = @_;
# assuming this class has more than just 'foo'...
unless (grep { $_ eq $key } @CLASS_KEYS ) {
croak (ref $self) . "has no $key member";
}
if ($key eq 'foo') {
$self->[1] = localtime(); # track last change
$self->[0] = $val;
$self->_recalculate_bar();
} else {
# set normal keys somehow
}
}
sub FETCH {
my ($self, $key, $val) = @_;
# assuming this class has more than just 'foo'...
unless (grep { $_ eq $key } @CLASS_KEYS ) {
croak (ref $self) . "has no $key member";
}
if ($key eq 'foo') {
$self->[2] = localtime(); # track last access
return $self->[0];
} else {
# get normal keys somehow
}
}
That would quickly become cumbersome though. |