Home > Archive > PERL Beginners > February 2006 > Why does my inheritance hierarchy get screwed up?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Why does my inheritance hierarchy get screwed up?
|
|
| Johannes Ernst 2006-02-22, 6:56 pm |
| [Blogged about it here: http://netmesh.info/jernst/Technical/perl-
inheritance-problem.html ]
There are three very simple classes in the following code: C is a
subclass of B, which is a subclass of A.
If I try to instantiate B (see last two lines of the code below), I'm
getting this output:
Point B: Exporter
Can't locate object method "new" via package "B" at madness.pl
line 23.
However, if I comment out class C (which isn't even instantiated by
my code!) it works!
It also works if I rename class B to Z, for example. And where in the
world would class Exporter suddenly come from? (see debugging output
of the @ISA)
Why would it do such a thing? Help!
Here is the code: (download from http://netmesh.info/jernst-files/
madness.txt )
#!/usr/bin/perl
package A;
use fields qw(a1 a2);
sub new {
my $self = shift;
$self = fields::new( $self ) unless( ref( $self ));
print "Point A: " . join( ", ", @ISA ) . "\n";
$self->{a1} = 'value of a1';
print "Setting value of a1\n";
return $self;
}
package B;
use base qw( A );
use fields qw(b1 b2);
sub new {
my $self = shift;
$self = fields::new( $self ) unless( ref( $self ));
print "Point B: " . join( ", ", @ISA ) . "\n";
$self->SUPER::new();
return $self;
}
package C;
use base qw( B );
use fields qw(c1 c2);
sub new {
my $self = shift;
$self = fields::new( $self ) unless( ref( $self ));
print "Point C: " . join( ", ", @ISA ) . "\n";
$self->SUPER::new();
return $self;
}
package Main;
my $obj = new B();
print "obj is $obj\n";
I tried this on v5.8.6 (OSX), v5.8.3 (Suse), and v5.8.0 (Red Hat);
same results.
| |
| Tom Phoenix 2006-02-22, 6:56 pm |
| On 2/22/06, Johannes Ernst <jernst+perl.org@netmesh.us> wrote:
> If I try to instantiate B (see last two lines of the code below), I'm
> getting this output:
>
> Point B: Exporter
> Can't locate object method "new" via package "B" at madness.pl
> line 23.
Did you know that B is a package name used internally by Perl? I think
that's the problem here. Change B to an unused package name, and
everything seems to work. Detecting package name collisions like this
is still an unsolved problem, alas, so that's one of the errors that
Perl can't warn you about.
Hope this helps!
--Tom Phoenix
Stonehenge Perl Training
| |
| Hans Meier 2006-02-22, 6:56 pm |
| Johannes Ernst am Donnerstag, 23. Februar 2006 00.19:
> [Blogged about it here: http://netmesh.info/jernst/Technical/perl-
> inheritance-problem.html ]
>
> There are three very simple classes in the following code: C is a
> subclass of B, which is a subclass of A.
>
> If I try to instantiate B (see last two lines of the code below), I'm
> getting this output:
>
> Point B: Exporter
> Can't locate object method "new" via package "B" at madness.pl
> line 23.
>
> However, if I comment out class C (which isn't even instantiated by
> my code!) it works!
>
> It also works if I rename class B to Z, for example. And where in the
> world would class Exporter suddenly come from? (see debugging output
> of the @ISA)
[...]
B is a core compiler module... this also explains where the Exporter in @ISA
is coming from, since B 'isa' Exporter.
It seems that - see to the order of paths in your @INC - the core B is loaded
and not your B.
Sorry, I did not delve deeper in your code.
hth
Hans
| |
| Johannes Ernst 2006-02-23, 9:55 pm |
| Thanks everybody pointing out that B is an internal Perl namespace.
Duh! I will refrain from comment on whoever made that choice ...
In addition, I realized that the order in which 'use' and 'use
fields' statements are made is very much significant; if one gets it
wrong, mysterious things happen and no error messages are printed. My
real code (not the snippet I sent) had something like this:
-- AA.pm --
package AA;
....
-- BB.pm --
package BB;
use AA;
use CC;
use base qw( AA );
use fields qw( b1 b2 );
....
-- CC.pm --
package CC;
use BB;
use base qw( BB );
....
My class BB imports CC because under one of its methods creates
instances of CC (which is supposed to be a subclass of BB). But
because I stated
'use CC'
before
'use base'
'use fields'
my file CC.pm would get read before BB was declared to be a child of
AA, and thus would never inherit the fields from AA or BB.
The correct sequence is this:
-- AA.pm --
package AA;
....
-- BB.pm --
package BB;
use AA;
use base qw( AA );
use fields qw( b1 b2 );
use CC; # <- after the 'use base' and 'use fields' statements
....
-- CC.pm --
package CC;
use BB;
use base qw( BB );
....
|
|
|
|
|