in reply to Prevent direct acces to object's attributes

Here is your module implemented as an inside-out class:
package MyMod; use strict; use warnings; use Carp; use Scalar::Util qw(refaddr); # Have a private hash for each attribute my %atr1; # Attribute 1 my %atr2; # Attribute 2 # etc. # This hash is used by the general purpose accessors my %hashrefs = ( atr1 => \%atr1, atr2 => \%atr2, #etc ); sub new { my $class = shift; my %args = @_; # create some unique number from a reference my $self = \do{my $dummy}; my $key = refaddr($self); $atr1{$key} = $args{'atr1'}; $atr2{$key} = $args{'atr2'}; # more attributes... bless($self, $class); # ... some code to populate attribs from passed parms return $self; } # General purpose get/set sub set { my ($self, $attr, $value) = @_; my $key = refaddr $self; if (exists $hashrefs{$attr} ) { $hashrefs{$attr}{$key} = $value } else { carp "Invalid attribute name $attr" } } sub get { my ($self, $attr) = @_; my $key = refaddr $self; if (exists $hashrefs{$attr} ) { return $hashrefs{$attr}{$key} } else { carp "Invalid attribute name $attr"; return; } } # MUST have a destructor sub DESTROY { my ($self) = @_; my $key = refaddr $self; delete $atr1{$key}; delete $atr2{$key}; # likewise for other attribute hashes } 1;
And here is the user code:
use strict; use warnings; use MyMod; my $mm = MyMod->new(atr1 => 1, atr2 => 'string2'); print $mm->get('atr1')."\n"; print $mm->get('atr2')."\n"; $mm->set('atr1', 42); print $mm->get('atr1')."\n"; $mm->{atr1} = 3000; <<<<---- Fails "Not a HASH reference"

Replies are listed 'Best First'.
Re^2: Prevent direct acces to object's attributes
by JavaFan (Canon) on Sep 08, 2009 at 10:11 UTC
    Your implementation is not going to work in a threaded environment, as memory addresses will change after a clone. You will have to implement a CLONE method as well.

    Or you could just use 5.10.x and use Hash::Util::FieldHash::fieldhash. Then the work needed in CLONE and DESTROY will be done for you, and you don't need refaddr either. Just use the reference itself as the hashkey.

    Hash::Util::FieldHash makes Inside-Out Objects much easier to work with. With it, I would write your example as:

    package MyMod; use strict; use warnings; use Carp; use Hash::Util::FieldHash qw[fieldhash]; fieldhash my %attr1; fieldhash my %attr2; my %hashrefs = ( attr1 => \%attr1, attr2 => \%attr2, ); sub new { my $class = shift; my %args = @_; my $self = bless do {\my $dummy}, $class; $attr1{$self} = $args{attr1}; $attr2{$self} = $args{attr2}; $self; } sub set { my ($self, $attr, $value) = @_; if (exists $hashrefs{$attr}) { $hashrefs{$attr}{$self} = $value } else { carp "Invalid attribute name $attr"; } } sub get { my ($self, $attr) = @_; if (exists $hashrefs{$attr}) { return $hashrefs{$attr}{$self} } else { carp "Invalid attribute name $attr"; return; } } 1;