I needed to do some fiddly method inheriting, and this implementation
for 'super' came to me. However, because of the way it searches
the superclass hierarchies, the AUTOLOADs in each superclass's
hierarchy are called BEFORE the next superclass hierarchy is
searched for the super-method. This could be considered a bug,
but is really a consequence of trying to use a single-inheritance
construct in a multiple-inheritence environment. The is-a semantics
in a single inheritance environment means that 'super' makes
sense there. But in a multiple inheritance environment, any particular
method should be reimplementing the behaviour of a particular
set of superclass hierarchies, and so should be calling
the appropriate superclass to lookup the super-method - i.e.
using the normal perl construct:
sub method {
...
#method need not be defined in superclass1, it just starts looking from there
->superclass1::method(...);
->superclass2::method(...);
...
}
whereas 'super' just trawls through all the hierarchy looking for any
implementation of 'method' - which is not really appropriate for MI.
A more efficient version of super than the one below (which would also
not suffer from the 'bug' outlined above) would be to temporarily undefine
the function, re-call it, then reassign it (like this: ' = \&meth;
undef(&meth); ->meth; *meth = ' ) but when I try this, I get
the "Can't undef active subroutine" error - I guess if its on the
stack this can't be done. Though I can't quite see if there is any
problem with the stack holding a reference to the function and still
allowing it to be undefined.
Example included - save everything after here in file 'super.pm' and
try 'perl -x super.pm'.
package super;
require Carp;
AUTOLOAD {
shift;
(my = ) =~ s/^.*:://;
package DB;
my() = caller(1);
package super;
my = ::args[0];
my = ref() || ;
my(@ret,,);
if (wantarray) {
foreach (@{ . '::ISA'}) {
= . '::' . ;
eval {@ret = ->(@_)};
|| return @ret;
=~ /^Can't locate object method/ || die ;
}
} else {
foreach (@{ . '::ISA'}) {
= . '::' . ;
eval { = ->(@_)};
|| return ;
=~ /^Can't locate object method/ || die ;
}
}
Carp::croak("Can't locate object method \"\" via superclasses of package \"\"");
}
1;
__END__
#!perl
#Example of using 'super'.
require super;
package A;
sub dib {print "Hello from 'dib' in package A: @_\n"}
package B;
sub dob {print "Hello from 'dob' in package B: @_\n"}
package C;
@ISA = qw(A B);
sub dib {print "Hello from 'dib' in package C: @_\n"}
sub dob {
print "Hello from 'dob' in package C: @_\n";
my = shift;
super->dob(@_); # super of this method
->dib(@_);
super->dib(@_); # super of another method
super->non_existent(@_); # And one to produce an error
}
C->dob(25,'arg2');
__END__
-- Jack Shirazi, JackS@slc.com
for 'super' came to me. However, because of the way it searches
the superclass hierarchies, the AUTOLOADs in each superclass's
hierarchy are called BEFORE the next superclass hierarchy is
searched for the super-method. This could be considered a bug,
but is really a consequence of trying to use a single-inheritance
construct in a multiple-inheritence environment. The is-a semantics
in a single inheritance environment means that 'super' makes
sense there. But in a multiple inheritance environment, any particular
method should be reimplementing the behaviour of a particular
set of superclass hierarchies, and so should be calling
the appropriate superclass to lookup the super-method - i.e.
using the normal perl construct:
sub method {
...
#method need not be defined in superclass1, it just starts looking from there
->superclass1::method(...);
->superclass2::method(...);
...
}
whereas 'super' just trawls through all the hierarchy looking for any
implementation of 'method' - which is not really appropriate for MI.
A more efficient version of super than the one below (which would also
not suffer from the 'bug' outlined above) would be to temporarily undefine
the function, re-call it, then reassign it (like this: ' = \&meth;
undef(&meth); ->meth; *meth = ' ) but when I try this, I get
the "Can't undef active subroutine" error - I guess if its on the
stack this can't be done. Though I can't quite see if there is any
problem with the stack holding a reference to the function and still
allowing it to be undefined.
Example included - save everything after here in file 'super.pm' and
try 'perl -x super.pm'.
package super;
require Carp;
AUTOLOAD {
shift;
(my = ) =~ s/^.*:://;
package DB;
my() = caller(1);
package super;
my = ::args[0];
my = ref() || ;
my(@ret,,);
if (wantarray) {
foreach (@{ . '::ISA'}) {
= . '::' . ;
eval {@ret = ->(@_)};
|| return @ret;
=~ /^Can't locate object method/ || die ;
}
} else {
foreach (@{ . '::ISA'}) {
= . '::' . ;
eval { = ->(@_)};
|| return ;
=~ /^Can't locate object method/ || die ;
}
}
Carp::croak("Can't locate object method \"\" via superclasses of package \"\"");
}
1;
__END__
#!perl
#Example of using 'super'.
require super;
package A;
sub dib {print "Hello from 'dib' in package A: @_\n"}
package B;
sub dob {print "Hello from 'dob' in package B: @_\n"}
package C;
@ISA = qw(A B);
sub dib {print "Hello from 'dib' in package C: @_\n"}
sub dob {
print "Hello from 'dob' in package C: @_\n";
my = shift;
super->dob(@_); # super of this method
->dib(@_);
super->dib(@_); # super of another method
super->non_existent(@_); # And one to produce an error
}
C->dob(25,'arg2');
__END__
-- Jack Shirazi, JackS@slc.com