A
Amir Karger
I've got a simple diamond class hierarchy (code below). In order to
bore people, I've chosen to use Vehicle as the base class.
SolarVehicle and WheeledVehicle inherit from Vehicle, and SolarCar
inherits from both of those child classes. (But you could have a
SolarSeaPlane that's a SolarVehicle and not a WheeledVehicle.)
I want to specify a new and an _init for the base class.
new just blesses {} and calls _init.
_init should call _init for every parent class, so that you initialize
all the attributes of the object, including attributes of the parent
classes along with this class.
So how do I write Vehicle::_init such that SolarCar::_init will
inherit it and call Vehicle::_init, SolarVehicle::_init, and
WheeledVehicle::_init? (Writing SolarCar::_init so that it overloads
Vehicle::_init and calls the parent class _init's separate would be
unelegant, it seems to me.)
I've written code below that does everything except the step of
getting the base classes. I feel like my problem here isn't that Perl
can't do it, but just a syntax problem. I really just want a "foreach
(@ISA)" - but how do I write an inheritable Vehicle::_init and refer
to @ISA such that the @ISA of the package in which _init is currently
running is used, instead of always @Vehicle::ISA or @{ref($self) .
"::ISA"}.
I don't *think* this problem is due to diamond inheritance per se as
much as multiple inheritance in general. Also, I have a feeling Damian
Conway's Objects book answers this but I no longer have it. Long
story.
HELP!
-Amir Karger
(e-mail address removed)
=cut
##################
package Vehicle;
@Vehicle::ISA = ();
sub new {
my ($class, %args) = @_;
print "new $class\n";
my $self = {};
bless $self, $class;
$self->_init(%args);
}
sub _init {
my ($self, %args) = @_;
my $class = ref $self or die "no class for $self\n";
print "_init for class $class.";
# Note: can't use $class . "::ISA", because $class will
# always be the class of the original object.
my @bases = EVERYTHING IN THIS CLASS' @ISA;
foreach my $base (@bases) {
my $c = $base . "::_init";
$self->$c(%args);
}
$self->_class_init(%args);
}
sub _class_init {
my ($self, %args) = @_;
$self->{"name"} = "Default vehicle name";
}
package WheeledVehicle;
@WheeledVehicle::ISA = qw(Vehicle);
sub _class_init {
my ($self, %args) = @_;
$self->{"wheels"} = 4;
}
package SolarVehicle;
@SolarVehicle::ISA = qw(Vehicle);
sub _class_init {
my ($self, %args) = @_;
$self->{"panels"} = 2;
}
package SolarCar;
@SolarCar::ISA = qw(WheeledVehicle SolarVehicle);
sub _class_init {
my ($self, %args) = @_;
$self->{"panels"} = 2;
}
#######################
bore people, I've chosen to use Vehicle as the base class.
SolarVehicle and WheeledVehicle inherit from Vehicle, and SolarCar
inherits from both of those child classes. (But you could have a
SolarSeaPlane that's a SolarVehicle and not a WheeledVehicle.)
I want to specify a new and an _init for the base class.
new just blesses {} and calls _init.
_init should call _init for every parent class, so that you initialize
all the attributes of the object, including attributes of the parent
classes along with this class.
So how do I write Vehicle::_init such that SolarCar::_init will
inherit it and call Vehicle::_init, SolarVehicle::_init, and
WheeledVehicle::_init? (Writing SolarCar::_init so that it overloads
Vehicle::_init and calls the parent class _init's separate would be
unelegant, it seems to me.)
I've written code below that does everything except the step of
getting the base classes. I feel like my problem here isn't that Perl
can't do it, but just a syntax problem. I really just want a "foreach
(@ISA)" - but how do I write an inheritable Vehicle::_init and refer
to @ISA such that the @ISA of the package in which _init is currently
running is used, instead of always @Vehicle::ISA or @{ref($self) .
"::ISA"}.
I don't *think* this problem is due to diamond inheritance per se as
much as multiple inheritance in general. Also, I have a feeling Damian
Conway's Objects book answers this but I no longer have it. Long
story.
HELP!
-Amir Karger
(e-mail address removed)
=cut
##################
package Vehicle;
@Vehicle::ISA = ();
sub new {
my ($class, %args) = @_;
print "new $class\n";
my $self = {};
bless $self, $class;
$self->_init(%args);
}
sub _init {
my ($self, %args) = @_;
my $class = ref $self or die "no class for $self\n";
print "_init for class $class.";
# Note: can't use $class . "::ISA", because $class will
# always be the class of the original object.
my @bases = EVERYTHING IN THIS CLASS' @ISA;
foreach my $base (@bases) {
my $c = $base . "::_init";
$self->$c(%args);
}
$self->_class_init(%args);
}
sub _class_init {
my ($self, %args) = @_;
$self->{"name"} = "Default vehicle name";
}
package WheeledVehicle;
@WheeledVehicle::ISA = qw(Vehicle);
sub _class_init {
my ($self, %args) = @_;
$self->{"wheels"} = 4;
}
package SolarVehicle;
@SolarVehicle::ISA = qw(Vehicle);
sub _class_init {
my ($self, %args) = @_;
$self->{"panels"} = 2;
}
package SolarCar;
@SolarCar::ISA = qw(WheeledVehicle SolarVehicle);
sub _class_init {
my ($self, %args) = @_;
$self->{"panels"} = 2;
}
#######################