http://qs1969.pair.com?node_id=514941

Inspired by the discussion of How to use Inheritance with Inside-Out Classes and Hash Based Classes, I have added the capability for Object::InsideOut objects to inherit from non-Object::InsideOut classes. (I refer to this as foreign inheritance in the POD.) Thus, using Object::InsideOut, you can now sub-class other Perl classes, and have access to their methods from your own inside-out objects.

Here's a quick-and-dirty sample that illustrates foreign inheritance using Object::InsideOut v1.18:

use strict; use warnings; # Borg is a foreign hash-based class package Borg; { # A regular hash-based constructor sub new { return (bless({}, shift)); } # A 'get' accessor sub get_borg { my ($self, $data) = @_; return ($self->{$data}); } # A 'put' accessor sub set_borg { my ($self, $key, $value) = @_; $self->{$key} = $value; } # A class method sub assimilate { return ('Resistance is futile'); } } # Foo is an Object::InsideOut class that inherits from class Borg package Foo; { use Object::InsideOut qw(Borg); # A data field with standard 'get_/set_' accessors my @foo :Field('Standard'=>'foo'); # Our class's 'contructor' sub init :Init { my ($self, $args) = @_; # Create a Borg object and inherit from it my $borg = Borg->new(); $self->inherit($borg); } # A class method sub comment { return ('I have no comment to make at this time'); } } package main; # Inheritance works on class m +ethods print(Foo->comment(), "\n"); # Call a 'native' class meth +od print(Foo->assimilate(), "\n"); # Call a 'foreign' class met +hod my $obj = Foo->new(); # Create our object $obj->set_foo('I like foo'); # Set data inside our object print($obj->get_foo(), "\n"); # Get data from our object $obj->set_borg('ID' => 'I am 5-of-7'); # Set data inside inherited ob +ject print($obj->get_borg('ID'), "\n"); # Get data from inherited obje +ct
Other points of interest:
  • Muliple inheritance is supported with any mix of Object::InsideOut and foreign classes.
  • The encapsulation of the inherited objects is strong, meaning that only the class where the inheritance takes place has direct access to the inherited object.
  • Disinheritance is supported to remove the association with an inherited object.
Any comments or suggestions from my fellow monks would be greatly appreciated. Enjoy.

Remember: There's always one more bug.

Replies are listed 'Best First'.
Re: Inside-out objects inheriting from hash-based classes
by xdg (Monsignor) on Dec 07, 2005 at 19:04 UTC

    You're innovating faster than I can keep up with it. :-)

    I'm glad to see this appear finally, as "foreign inheritance" is one of the other big deals of the inside-out technique. (I like that term -- I've been searching for a good term for it for the seminar that I mentioned in Seeking inside-out object implementations, so I'll have to steal it and credit you.)

    Can you talk about the design choices you've made a little bit more? From a quick skim of the code, it looks like you're using some sort of facade pattern (er, adaptor pattern, whatever) in the AUTOLOAD to check method calls against the foreign object(s), rather than using a foreign object as the blessed reference directly with the @ISA array. That does allow multiple foreign objects, but at the cost of incremental indirection.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      You're innovating faster than I can keep up with it. :-)
      Yes. I'm trying to make Object::InsideOut as comprehensive as possible, hoping that will induce people to try it.
      Can you talk about the design choices you've made a little bit more? From a quick skim of the code, it looks like you're using ... AUTOLOAD to check method calls against the foreign object(s), rather than using a foreign object as the blessed reference directly with the @ISA array. That does allow multiple foreign objects, but at the cost of incremental indirection.
      Yes, the foreign method dispatching is done in AUTOLOAD. That was the suggested techique from the discussions I read. This allowed me to support multiple inheritance, as well. True, there is a performance trade-off with this form of dispatching, but it does provide maximal functionality.

      The other feature this design provides is encapsulation. The foreign object is hidden from all but the inheriting class's code. This allows the class code to control access to the guts of hash-based objects.


      Remember: There's always one more bug.

        But what happens if you need/want to make explicit calls to a super class?

        print( $object->Borg::comment(), "\n" );

        Updated/expanded for clarity

        Assume that you have a method of the same name in Borg as you do in Foo:

        package Borg; sub comment { return $_[0]->{default_threat}; }

        If I want to explicitly call the Borg version of that method, I'd call it as $obj->Borg::comment(). However, that's equivalent to this:

        Borg::comment( $obj );

        Therefore, if Borg::comment is expecting an object of type Borg and intends to muck with its internal structure directly, this will fail since the real Borg object is hidden in a closure in Foo and keyed to $obj and $obj is just the blessed reference for the inside-out object.

        Or have I missed something?

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: Inside-out objects inheriting from hash-based classes
by ghenry (Vicar) on Dec 08, 2005 at 08:47 UTC