Hack 43. Turn Your Objects Inside Out


Encapsulate your attributes strongly.

Perl 5's object orientation is minimalistic. It gives you enough to get the job done while not preventing you from doing clever things. Of course, the default approach is usually the simplest one (or the cleverest), not the cleanest or most maintainable.

Most objects are blessed hashes, because they're easy to understand and to use. Unfortunately, they can be difficult to debug and they don't really provide any encapsulation, thus tying you to specific implementation schemes.[1]

[1] See "Seven Sins of Perl OO Programming" in The Perl Review 2.1, Winter 2005.

Fortunately, fixing that is easy.

The Hack

An object in Perl needs two things, a place to store its instance data and a class in which to find its methods. A blessed hash (or array, or scalar, or subroutine, or typeglob, or...) stores its data within the object you pass around. If you dereference the reference, you can read and write that data from anywhere, even outside the class.

An inside out object stores its data elsewhere, often in a lexical variable scoped to the class. From outside the lexical scope, you can't (usuallysee "Peek Inside Closures" [Hack #76]) access that data without using the object's accessors.

Damian Conway's first book, Object Oriented Perl (Manning, 2000) showed various ways to use closure-based encapsulation. His recent Perl Best Practices (O'Reilly, 2005) recommended using them as a best practice. The Perl hacker known simply as Abigail has also touted the virtues of inside out objects for several years. See the documentation of Class::Std for a fuller treatment of the issue.


Running the Hack

A simple, naïve inside out object implementation for a record class might be:

# create a new scope for the lexicals {     package InsideOut::User;     use Scalar::Util 'refaddr';     # lexicals used to hold instance data     my %names;     my %addresses;     sub new     {         my ($class, $data) = @_;         # bless a new scalar to get this object's id         bless \\(my $self), $class;         # store the instance data         my $id             = refaddr( $self );         $names{     $id }  = $data->{name};         $addresses{ $id }  = $data->{address};         return $self;     }     # accessors, as $self->{name} and $self->{address} don't work     sub get_name     {         my $self = shift;         return $names{ refaddr( $self ) };     }     sub get_address     {         my $self = shift;         return $addresses{ refaddr( $self ) };     }     # many people forget this part     sub DESTROY     {         my $self = shift;         my $id   = refaddr( $self );         delete $names{     $id };         delete $addresses{ $id };     } } 1;

That's a little more typing, but it's definitely a lot cleaner. Now you can subclass or reimplement InsideOut::User without having to use a blessed hashjust follow the interface this defines and your code will work.

Of course, the more complex the object, the more typing you have to do. Wouldn't it be nice to automate this?

Hacking the Hack

Class::Std, Class::InsideOut, and Object::InsideOut are three current modules on the CPAN that take some of the work out of inside out objects for you. They all have various tricks and features. Class::Std is nice in that it automatically creates accessors and mutators, calls better constructors and destructors, and uses a declarative attribute-based syntax [Hack #45].

The same class using Class::Std is:

{     package InsideOut::User;     use Class::Std;     my %names     :ATTR( :get<name>    :init_arg<name>    );     my %addresses :ATTR( :get<address> :init_arg<address> ); }

This code automatically generates the get_name( ) and get_address( ) accessors as well as a constructor that pulls the initial values for the objects out of a hash reference with the appropriate keys. The syntax isn't quite as nice as that of Perl 6, but it's much, much shorter than the naïve Perl 5 versionand provides all of the same features.



Perl Hacks
Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving
ISBN: 0596526741
EAN: 2147483647
Year: 2004
Pages: 141

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net