Thread

Posted on Mon Jan 30 20:18:56 2006 by earl
Getting a foreign class pushed onto the @ISA array

When given a foreign class inheritance, why doesn't this code segment push that class name onto the @ISA array?

foreach my $parent (@packages) { if (exists($TREE_TOP_DOWN{$parent})) { # Inherit from Object::InsideOut class foreach my $ancestor (@{$TREE_TOP_DOWN{$parent}}) { if (! exists($seen{$ancestor})) { push(@tree, $ancestor); $seen{$ancestor} = undef; } } push(@{$class.'::ISA'}, $parent); $need_oio = 0; } else { # Inherit from foreign class # Get inheritance 'classes' hash if (! exists($HERITAGE{$class})) { create_heritage($class); } my $classes = $HERITAGE{$class}[1]; # Add parent to inherited classes $classes->{$parent} = undef; } }

I have an inside out class IOC that ISA PVC class. PVC in a pure virtual class and therefore a foreign class. Within the IOC package, I have the ...

use Object::InsideOut qw/PVC/;

When I use IOC and print out it's @ISA array, PVC is not there. I looked at the Object::InsideOut code that mutates @ISA. I thought it should push inherited foreign class onto @ISA. What should I do to get PVC onto the @ISA array?

Earl
Direct Responses: 1723 | Write a response
Posted on Mon Jan 30 23:30:17 2006 by jdhedden in response to 1721
Re: Getting a foreign class pushed onto the @ISA array
    What should I do to get PVC onto the @ISA array?

Technically, @ISA arrays are private to their classes, and cannot be relied on to directly determine inheritance. The correct manner is to use the ->isa() method which can be overriden by classes (as is the case with Object::InsideOut) to provide correct inheritance information.

Only Object::InsideOut classes are put into the @ISA array. Foreign inheritance is handled via Object::InsideOut's version of the ->isa() method, and in its AUTOLOAD subroutine.
Direct Responses: 1724 | Write a response
Posted on Tue Jan 31 04:23:49 2006 by earl in response to 1723
Re: Getting a foreign class pushed onto the @ISA array

Since my understanding of inheritance in Perl is based on using @ISA, I am confused. In an object method invokation, how does an IOC object inherit the PVC methods/subroutines?

The Object::InsideOut section on Foreign class inheritance says ...

One method of declaring foreign class inheritance is to add the class name to the Object::InsideOut declaration inside your package:

package My::Class; { use Object::InsideOut qw(Foreign::Class); ... }

This allows you to access the foreign class's static (i.e., class) methods from your own class. For example, suppose Foreign::Class has a class method called foo. With the above, you can access that method using My::Class->foo() instead.

What about the foreign class's object methods? IMHO, the @ISA array is central to how inheritance works. If the class name is not in the @ISA array, I worry that IOC won't be able to inherit the PVC's methods.

Direct Responses: 1725 | Write a response
Posted on Tue Jan 31 13:07:36 2006 by berkan in response to 1724
Re: Getting a foreign class pushed onto the @ISA array
What about the foreign class's object methods? IMHO, the @ISA array is central to how inheritance works. If the class name is not in the @ISA array, I worry that IOC won't be able to inherit the PVC's methods.

hi earl,

i hope jerry doesn't mind me answering [i've been looking into the OIO code and may as well share].

just after the section you've quoted, the documentation says:

$self->inherit($obj, ...);

To use object methods from foreign classes, an object must inherit from an object of that class. This would normally be done inside a class's :Init subroutine [...]
sub init :Init { my ($self, $args) = @_; my $foreign_obj = Foreign::Class->new(...); $self->inherit($foreign_obj); }


All such inherit'ed foreign objects are put into a heritage array, which the OIO AUTOLOAD function [called for a method that your inherit'ing class doesn't know how to handle] walks through to find an object that it can delegate the method to.

hope this helps,

berkan
Direct Responses: 1727 | Write a response
Posted on Tue Jan 31 15:46:17 2006 by earl in response to 1725
Re: Getting a foreign class pushed onto the @ISA array

I just want to say that I REALLY, REALLY like this module. It's amazing. I'm impressed that there is support for foreign classes. And I'm trying not be negative.

Having said that, what are the consequences of just doing a "use base" to get the modules on the @ISA array? Would this break the Object::InsideOut module?

My pure virtual class PVC doesn't have a "new" subroutine. A pure virtual class just provides a list of subroutines that all subclasses should implement. Furthermore, PVC doesn't make any commitment to the representation of the blessed object. You could have an inside out subclass and a hash-based subclass that are PVCs. Likewise, it doesn't make sense to create an object from a pure virtual class, because the subroutines are not implemented. See the Class::Virtual module.

Earl
Direct Responses: 1728 | Write a response
Posted on Tue Jan 31 17:42:37 2006 by jdhedden in response to 1727
Re: Getting a foreign class pushed onto the @ISA array
An inheritance chain consists of two pieces: @ISA arrays, and AUTOLOAD subroutine(s).

When a class (object) method is invoked, Perl first checks for the method in the designated class (object's class). Then it searches recursively through the classes' @ISA arrays in a depth-first, left-to-right manner. If the method is still not found, Perl searches for an AUTOLOAD subroutine using the same strategy. If an AUTOLOAD subroutine is found, it is invoked. If the AUTOLOAD subroutine fails, no further searching occurs; the method call fails.

In the case of Object::InsideOut, foreign inheritance is handled in the AUTOLOAD subroutine only: Foreign classes are not put in the @ISA array. Foreign objects and classes are maintained in separate data structures inside Object::InsideOut. When invoked, Object::InsideOut's AUTOLOAD subroutine handles the details of searching through those objects and classes to find the appropriate method, and invokes it according to the following scheme:

1. If an object method is being invoked, and there is a corresponding foreign object (i.e., designated using $obj->inherit($foreign)), then the object method is invoked via the foreign object (i.e., equivalent to $foreign->method()).

2. If an object method is being invoked, and there is a no corresponding foreign object, then the method in the foreign class is invoked with the calling object (i.e., equivalent to $obj->method()).

3. Finally, if a class method is being invoked (i.e., no objects are involved), then the class method is invoked via the foreign class (i.e., equivalent to Foreign->method()).

The motivating case for this methodology is driven by the requirement that for most classes their object methods expect to be invoked via their own objects. (The third case above is done for consistency with how object methods are being invoked.)

The rule specified in the POD to not 'use base' (or equivalently to manipulate the @ISA arrays) for foreign inheritance reflects the above design considerations and implementation. But, of course, there are exceptions to every rule.

Here are the exceptions, and the proposed methodologies for handling each:

1. Foreign object methods that expect to be invoked via the inheriting class's object.

In this case, you can either invoke the method using its full path (e.g., $obj->Foreign::Class::method(); ), or you can 'use base' so that you don't have to use the full path for foreign methods. The former scheme is faster.

2. Foreign object methods that don't care how they are invoked (i.e., they don't make reference to the invoking object).

In this case, either method of including the foreign class can be used. Use 'use Object::InsideOut qw(Foreign::Class);' for consistency, or use 'use base qw(Foreign::Class);' if better performance is needed.

3. Foreign class methods that expect to be invoked via the inheriting class.

As with the case for similar object methods describe above, you can either invoke the method using its full path (e.g., My::Class->Foreign::Class::method(); ), or you can 'use base' so that you don't have to use the full path. Again, using the full path is faster.

Class::Singleton is an example of this type of class.

4. Class methods that don't care how they are invoked (i.e., they don't make reference to the invoking class).

Again, either method of including the foreign class can be used. Use 'use Object::InsideOut qw(Foreign::Class);' for consistency, or use 'use base qw(Foreign::Class);' if better performance is needed.

If you're not familiar with the inner workings of the foreign class such that you don't know if or which of the above exceptions applies, then the formulaic approach would be to first use the documented method for foreign inheritance (i.e., use Object::InsideOut qw(Foreign::Class); ). If that works, then you're done. If that doesn't work, then try 'use base'.

That's the long of it. Hope this helps.
Direct Responses: 1729 | Write a response
Posted on Tue Jan 31 18:07:36 2006 by jdhedden in response to 1728
Re: Getting a foreign class pushed onto the @ISA array
Correction. Replace exception cases 1 and 2 with:

1. Foreign object methods that expect to be invoked via the inheriting class's object, or foreign object methods that don't care how they are invoked (i.e., they don't make reference to the invoking object).

This is the case where a class provides auxiliary methods for your objects, but from which you don't actually create any objects (i.e., there is no corresponding foreign object, and $obj->inherit($foreign) is not used.)

In this case, you can either invoke the methods using their full path (e.g., $obj->Foreign::Class::method(); ), or you can 'use base' so that you don't have to use the full path for foreign methods. The former scheme is faster.
Write a response