Class::Tie::InsideOut - Inside-out objects on the cheap using tied hashes



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 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.

Serialization and Cloning

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.)


KNOWN ISSUES

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.


SEE ALSO

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


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 the Class::Accessor manpage.

Suggestions and Bug Reporting

Feedback is always welcome. Please use the CPAN Request Tracker at http://rt.cpan.org to submit bug reports.


LICENSE

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.