[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