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