Default Perl accessor for objects

Viewed 84

If I have a Perl class eg

package Foo;

sub new {
    my ($class,$hashref) = @_;
    my $self = bless $hashref, $class;
}

and initialised with

my $foo = Foo->new( { bar => 2, othervar => 8 } );

I can do

print $foo->{ bar };

which feels clunky, and

print $foo->bar

feels more preferable. However, if there are a lot of keys, I'd prefer not to have to write an accessor for every key (or is that best practice) ?

So, I can include

our $AUTOLOAD;
sub AUTOLOAD {
    my $self = shift;

    my $called =  $AUTOLOAD =~ s/.*:://r;

    die "No such attribute: $called"
        unless exists $self->{$called};

    return $self->{$called};
}

sub DESTROY { } # see below

In perldoc perlobj it says # XXX - this is a terrible way to implement accessors

Are there any good ways to implement accessors like this, without using other packages, eg Moose, Class::Accessor ? I'm just after something light as its just one class that has a lot of keys.

1 Answers

Are there any good ways to implement accessors like this, without using other packages ...

If you insist, then write those subs directly to the package symbol table

package AutoAccessors;

use warnings;
use strict;
use feature 'say';

my @attr_names;

BEGIN {
    @attr_names = qw(name mode etc);
    no strict 'refs';
    foreach my $accessor (@attr_names) {
        *{$accessor} = sub { do {
            if    (@_ == 1) { $_[0]->{$accessor} }
            elsif (@_ == 2) { $_[0]->{$accessor} = $_[1] }
            #elsif ...
        } };
    }
};


sub new {
    my ($class, $args) = @_;
    my $self;
    foreach my $attribute (@attr_names) {
        # Check, initialize, set from $args, etc 
        $self->{$attribute} = $args->{$attribute} if $args->{$attribute};
    }   
    return bless $self, $class;
}   

1;

Then

use warnings;
use strict;
use feature 'say';

use AutoAccessors;

my $obj = AutoAccessors->new({ mode => '007' }); 

$obj->name('Bond');
say "name's ", $obj->name;
say "mode:  ", $obj->mode;

This is done in a number of CPAN packages (and it's usually more elaborate).

Having said that, I see no good reason to avoid good libraries, far more carefully done and complete. For instance, Moo as a full system comes in at around 5 kloc (if I recall correctly) and has barely a handful of dependencies, while Class::Accessor is just over 200 loc with one dependency that I can see.

Related