How should I access instance data in a Perl subclass?


How should I access instance data in a Perl subclass?



I am extending a module and I want some tips on good practices. Specially namespace conflicts: what exactly are they and how to avoid them.

When extending, should I not access variables in the SUPER class and only alter its state through accessors or object methods? What to do in case there are no (or limited) accessors? Am I "allowed" to access these object variables directly?

Cheers!




Perl and Moose: What Moose-based package should I use as replacement for MooseX::Method

1:



How to enable msg and debug logging with Log::Message::Simple
It is best to only access things through accessors because this prevents changes in the implementation of the superclass from affecting the subclasses.


How to create POD and use pod2usage in perl?
You should stay far away from anything that starts with an underbar.


How do I insert a line at a specific row in multiple files on Unix?
Those things are private to the class.


How can run an operation on one column of an CSV file in Perl?
Try to stay away from anything that is not documented.


Is there a Perl module that works similarly to the Unix “which” command?
Relying on those things will get you into trouble.


How can I compare lines in a file using Perl?
Also, consider using has-a versus is-a relationship..
Perl script to run a C executable with an argument while giving standard input through a file?
Let's imagine a widget class.

This class has name and price members (note, none of this is particularly good code, I have just tossed of a version with out thinking about it for the sake of an example):.
package Widget;  use strict; use warnings;  sub new {    my $class = shift;    my %args  = @_;     return bless {        price => $args{price} || 0,        name  => $args{name}  || "unkown",    }, $class; }  sub price { shift->{price} } sub name  { shift->{name}  }  1; 
You decide to subclass widget to add a weight member:.
package Widget::WithWeight;  use strict; use warnings;  use base 'Widget';  sub new {     my $class = shift;     my %args  = @_;     my $self  = $class->SUPER::new(%args);     $self->{weight} = $args{weight} || 0;     return bless $self, $class; }  sub weight { shift->{weight} }  sub price_per_pound {     my $self = shift;     return $self->{price}/$self->{weight}; }  1; 
Now imagine the author of the first module changes his/her mind about how to store the price.

Perhaps it was stored as a floating point number and the author realized that storing it as an integer number of pennies would be better:.
package Widget;  use strict; use warnings;  sub new {    my $class = shift;    my %args  = @_;     if ($args{price}) {                   $args{price} =~ s/[.]//;    }     return bless {        price => $args{price} || "000",        name  => $args{name}  || "unkown",    }, $class; }  sub price {      my $self = shift;     my $price = $self->{price};     substr($price, -2, 0) = ".";     return $price; }  sub name  { shift->{name}  }  1; 
Suddenly, your tests will start failing, but if you had used the price accessor instead, you would have been insulated from that change..


2:


Namespace conflicts can happen if you inherit from two modules into one and they both provide (export) the same sub.. I suggest you have a look at Moose, an extension to Perl that provides you with classes and roles.

You can avoid many conflicts if you use roles.

See http://www.iinteractive.com/moose/ . Moose also makes automatic accessors for the class variables, making it safer to access them from inheriting classes..



82 out of 100 based on 42 user ratings 742 reviews