[Bioperl-l] multiple inheritance

Lincoln Stein lstein at cshl.edu
Tue Sep 9 18:03:00 EDT 2003


I know I'm responding kind of late, but the easiest way to weasle out of this 
one is just to explicitly call new() in both parents.

	sub new {
		my $class = shift;
		my $self = $class->B::new(@_);
		$self->C::new(@_);
	}

Or you can generalize this:

	sub new {
		my $class = shift;
		my $self = $class;
		for my $parent (@ISA) {
			my $method = "$parent\:\:new";
			$self = $self->$method(@_);
		}
		$self;
	}

Note that  A will end up being invoked twice (oops) and that the initializer 
must be prepared to receive a first argument containing an initialized object 
rather than a class name.  NEXT will solve the first problem, but not the 
second.

Better perhaps would be to separate object creation from initialization in all 
classes:

	sub new {
		my $class = shift;
		my $self = bless {},ref $class || $class;
		$self->initialize(@_);
	}

This way one would never override new() and instead would inherit like this:

	sub initialize {
		my $self = shift;
		for my $parent (@ISA) {
			next unless $parent->can('initialize');
			my $method = "$parent\:\:initialize";
			$self->$method(@_);
		}
	}

There's probably a clever way to turn this into a method that can be called in 
the Bio::Root class.  Let's see:

	sub initialize_chain {
		my $self = shift;
		my $package = ref $self;
		for my $parent (@{"$package\:\:ISA"}) {
			next unless $parent->can('initialize');
			my $method = "$parent\:\:initialize";
			$self->$method(@_);
		}
	}

So now we override with:
		sub initialize {
			my $self = shift;
			$self->initialize_chain(@_);
			# now do our own initialization
		}

A little more work and we can prevent the base class from initializing twice.

Lincoln

	
On Wednesday 30 July 2003 04:12 pm, Jason Stajich wrote:
> Hmm - how should we solve the multiple inheritance when we want to chain
> both constructors.  Using SUPER just goes up the tree and will follow B
> first up to A and never call C's constructor.
>
> package D;
> @ISA = qw(B C);
>
>    A
>   / \
>   B C
>   \ /
>    D
>
>
> The Right Way* to do this is of course not having multiple inheritance OR
> to use The Damian's NEXT
> http://search.cpan.org/author/DCONWAY/NEXT-0.50/lib/NEXT.pm
>
> We run into this for SeqFeature::SimilarityPair which ISA FeaturePair and
> a Similarity - the soln there was not to rely on the constructor for
> initializing parameters.
>
> I am hitting it again for my Tree::AlleleNode objects which are
> PopGen::Individuals (genotype containers) and Tree::Node (as part of the
> coalescent).
>
> My soln will be to explictly code all the initialization parameters for
> the skipped superclass (C as in above example) as copy+paste
>
> NEXT is part of perl 5.8.0 and would remove a lot of issues wrt to
> chaining destructors that we have some code hacks for in Bio::Root::Root.
> But I am wary of adding another module dependancy.
>
> Comments?
>
> --
> Jason Stajich
> Duke University
> jason at cgt.mc.duke.edu
> _______________________________________________
> Bioperl-l mailing list
> Bioperl-l at portal.open-bio.org
> http://portal.open-bio.org/mailman/listinfo/bioperl-l

-- 
Lincoln Stein
lstein at cshl.edu
Cold Spring Harbor Laboratory
1 Bungtown Road
Cold Spring Harbor, NY 11724
(516) 367-8380 (voice)
(516) 367-8389 (fax)


More information about the Bioperl-l mailing list