Why not adopt me?
NAME
Class::Tie::InsideOut - Inside-out objects on the cheap using tied hashes
SYNOPSIS
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
}
DESCRIPTION
This module is a proof-of-concept for implementing inside-out objects using tied hashes. It makes use of the Tie::InsideOut 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 Class::Tie::InsideOut 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 Class::Tie::InsideOut 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.
Serialization and Cloning
You can use Storable to serialize clone objects, since there are hooks in Tie::InsideOut 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.)
KNOWN ISSUES
When a class is inherited from from a Class::Tie::InsideOut 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 Clone and Data::Dumper will not work properly.
To use with packages which generate accessor methods such as Class::Accessor 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 Sub::Name to rename subroutines:
use Sub::Name;
$accessor = subname "${class}::${field}" => sub {
my $self = shift;
...
};
However, Sub::Name 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 Tie::InsideOut or Class::Tie::InsideOut global hash variable as a key for itself, which has unpredicable (and possibly dangerous) results.
SEE ALSO
This module is a wrapper for Tie::InsideOut.
There are various other inside-out object packages on CPAN. Among them:
Class::InsideOut
Class::Std
Object::InsideOut
AUTHOR
Robert Rothenberg <rrwo at cpan.org>
Acknowledgements
Thanks to Ovid (via Chromatic) and Steven Little for advice in PerlMonks on the namespace issues with Class::Accessor.
Suggestions and Bug Reporting
Feedback is always welcome. Please use the CPAN Request Tracker at http://rt.cpan.org to submit bug reports.
STATUS
This module has not been seriously updated since 2006, and inside-out objects have largely fallen out of favor since then.
It has been marked as ADOPTME
on CPAN.
LICENSE
Copyright (c) 2006,2014 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.