Class::Tie::InsideOut - Inside-out objects on the cheap using tied hashes
package MyClass;
use Class::Tie::InsideOut;
our @ISA = qw( Class::Tie::InsideOut );
our %GoodKey;
sub bad_method { my $self = shift; return $self->{BadKey}; # this won't work }
sub good_method { my $self = shift; return $self->{GoodKey}; # %GoodKey is defined }
This module is a proof-of-concept on of implementing inside-out objects using tied hashes. It makes use of the the Tie::InsideOut manpage package to tie hash keys to hashes in the calling package's namespace.
Fields are accessed as hash keys, so in traditional Perl objects can be easily converted into inside-out objects.
To use, inherit our class from the Class::Tie::InsideOut manpage and then specify the legal keys for your object to use as hashes within the classes namespace:
package MyClass;
use Class::Tie::InsideOut;
our @ISA = qw( Class::Tie::InsideOut );
our (%Field1, %Field2, %Field3 ); # Fields used by MyClass
Note that your keys must be specified as our variables so that they are accessible
from outside of the class, and not as my variables!
Fields are accessed as hash keys from the object reference:
sub method { my $self = shift; if (@_) { $self->{Field1} = shift; } else { return $self->{Field1}; } }
Converting a Perl module which uses "traditional" objects into one which
uses inside-out objects can be a matter of adding the Class::Tie::InsideOut manpage
to the @ISA list and adding the field names as global hashes.
However, if child classes do not use parent class methods to access fields in the parent class, then there will be problems. See the KNOWN ISSUES section below.
You can use the Storable manpage to serialize clone objects, since there are hooks in the Tie::InsideOut manpage which allow for this. To add a clone method to your class:
use Storable qw( dclone );
...
sub clone { my $self = shift; my $clone = dclone($self); return $clone; }
But be aware that if the structure of parent classes are changed, then you may not be
able to deserialize objects. (The same can happen with tradititional classes,
but Tie::InsideOut will catch this and return an error.)
When a class is inherited from from a the Class::Tie::InsideOut manpage class, then it too must be an inside out class and have the fields defined as global hashes. This will affect inherited classes downstream.
Child classes cannot directly access the fields of parent classes. They must use appropriate accessor methods from the parent classes. If they create duplicate field names, then those fields can only be accessed from within the those classes.
As a consequence of this, objects may not be serializable or clonable out of the box. Packages such as the Clone manpage and the Data::Dumper manpage will not work properly.
To use with packages which generate accessor methods such as
the Class::Accessor manpage with this, you'll need to define the set and get
methods inside of your class.
Accessor-generating packages which do not make use of an intermediate method are not compatible with this package. This is partly a Perl issue: the caller information from closures reflects the namespace of the package that created the closure, not the actual package that the closure resides. However, the issue is fixable. The subroutine needs to set its namespace:
$accessor = sub { local *__ANON__ = "${class}::${field}"; my $self = shift; ... };
Another alternative is to use the Sub::Name manpage to rename subroutines:
use Sub::Name;
$accessor = subname "${class}::${field}" => sub { my $self = shift; ... };
However, the Sub::Name manpage uses XS and is not a pure-Perl solution.
This version does little checking of the key names, beyond that there is a
global hash variable with that name in the namespace of the method that
uses it. It might be a hash intended as a field, or it might be one intended
for something else. (You could hide them by specifying them as my variables, though.)
There are no checks against using the name of a tied the Tie::InsideOut manpage or the Class::Tie::InsideOut manpage global hash variable as a key for itself, which has unpredicable (and possibly dangerous) results.
This module is a wrapper for the Tie::InsideOut manpage.
There are various other inside-out object packages on CPAN. Among them:
Class::InsideOut Class::Std Object::InsideOut
Robert Rothenberg <rrwo at cpan.org>
Thanks to Ovid (via Chromatic) and Steven Little for advice in PerlMonks on the namespace issues with the Class::Accessor manpage.
Feedback is always welcome. Please use the CPAN Request Tracker at http://rt.cpan.org to submit bug reports.
Copyright (c) 2006 Robert Rothenberg. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.