[Bioperl-l] Re: Automatic generation of set and get methods
Lincoln Stein
lstein@cshl.org
Thu, 14 Nov 2002 12:11:34 -0800
Hi Nat,
Both of these techniques (autoload and autogeneration) are used extensively in
other Perl modules. In fact, there are several CPAN modules in the Class::
subdirectory that make it even easier. For example, have a look at the
Class::MakeMethods synopsis:
NAME
Class::MakeMethods - Generate common types of methods
SYNOPSIS
package MyObject;
use Class::MakeMethods::Basic::Hash (
'new' => [ 'new' ],
'scalar' => [ 'foo', 'bar' ]
);
package main;
my $obj = MyObject->new( foo => "Foozle", bar => "Bozzle" );
print $obj->foo();
$obj->bar("Barbados");
Why aren't they used in BioPerl? Because support for AUTOLOAD and BEGIN were
shaky prior to perl 5.4, and Bioperl wanted to remain 5.00503 compatible for
a long time. This restriction is now gone, and I think that you'll be seeing
more of this style in coming modules.
One problem with the code you quote from Bio::Index::Abstract is that it
provides no way to unset an instance variable. For example:
$object->foo(undef);
will *NOT* work, because the argument is undefined. I consider this a
misfeature. We had a thread about this on bioperl-l mailing list a month or
so ago and I'm surprised it isn't fixed by now. A better idiom is this:
*$func = sub {
my $self = shift;
my $current = $self->{$field};
$self->{$field} = shift if @_;
return $current;
}
This also has the advantage of preserving the semantics of simultaneous
get-and-set, and is consistent with LWP and other widely used modules. The
get part returns the existing value of the field, and the set part sets the
new value.
Lincoln
On Friday 08 November 2002 09:53 am, Nathan \(Nat\) Goodman wrote:
> Hi Lincoln
>
> I have a Perl style question that maybe you can help me with.
>
> I noticed the following neat code in Bio::Index::Abstract to automatically
> create set and get methods for simple attributes.
>
> BEGIN {
> foreach my $func (qw(filename write_flag)) {
> no strict 'refs';
> my $field = "_$func";
>
> *$func = sub {
> my( $self, $value ) = @_;
>
> if (defined $value) {
> $self->{$field} = $value;
> }
> return $self->{$field};
> }
> }
> }
>
> This seems so elegant, I wonder why it’s not used everywhere in BioPerl.
> Is there some hidden problem?
>
> Along the same lines, why not use AUTOLOAD to do the same thing? AUTOLAD
> could be programmed to look in @ATTRIBUTES before blithely creating the
> function if one wanted to introduce a bit of sanity. Is there a big
> performance hit here?
>
> Thanks,
> Nat