in reply to my $self is stumped!

Oh great monks...

Thanks for these responses, they are very interesting. But I can't seem to convince myself that there's no way for a parent class to access it's own methods without being explicitly passed a reference to an object of it's type.

An additional puzzle: why doesn't this work?
if ( ref($self) eq 'person') { $self->tellName(); } if ( ref($self) eq 'child') {$self->SUPER::tellName();}
When I put that into person::introduce, I get this:
Hello, I'm Alice. Hi, I'm Billy The Kid. Can't locate object method "tellName" via package "person" at ./classt +est line 25. Here's my mom: Hello, I'm

Which seems to tell me that even when $self was passed in from a child object, it's trying to locate SUPER::tellName inside of package "person".

Am I interpreting that correctly?

Complete code with above modification:
#!/usr/bin/perl use strict; package person; sub new { my $class = shift(@_); my $self = { 'name' => 'Alice' }; bless($self, $class); return($self); } sub tellName { my($self)=$_[0]; print "$self->{'name'}.\n"; } sub introduce { my($self)=$_[0]; print "Hello, I'm "; # $self->tellName(); # original code # tellName($self); # one solution offered by perlmonks #print "\ndebug info: " . ref($self) . "\n"; if ( ref($self) eq 'person'){ $self->tellName(); } if ( ref($self) eq 'child') { $self->SUPER::tellName();} } 1; package child; our @ISA = qw(person); # inherits from person sub new { my $class = shift(@_); my $self = $class->SUPER::new(); $self ->{'nickName'} = 'Billy The Kid'; bless $self, $class; return $self; } sub tellName { my($self)=$_[0]; print "$self->{'nickName'}.\n"; } sub introduce { my($self)=$_[0]; print "Hi, I'm "; $self->tellName(); print "Here's my mom: "; $self->SUPER::introduce(); } 1; package main; my $mom = new person(); $mom->introduce(); # that time it works. print "\n"; my $son = new child(); $son->introduce();

Replies are listed 'Best First'.
Re^2: my $self is stumped!
by eric256 (Parson) on Jun 18, 2007 at 18:05 UTC

    When one class uses another as its base, and then overrides it, you want that behavior. Sometimes it would be nice for the parent class to be able to take control, but if that where the case then you would have a hard time subclasses other peoples modules to make them do what you want. Realy you just need to look at the problem differently. Since you are making objects you want to think about the actual objects, not the classes. The classes are just a template to build objects with. So your 'person' class isn't 'Alice', it is just a template you are going to use to make the object that will be 'Alice'. In the same fashion your 'child' class isn't 'Billy the kid', it is just a template for an object that has a name, and knows its parents. So when you create the child object you want to tell it it's name and then tell it who its parents are by passing its parents to it as objects. I have modified your code to do exactly that below.

    #!/usr/bin/perl use strict; { package person; #basic person sub new { my ($class, $name) = @_; my $self = { 'name' => $name }; bless $self, $class; return $self; } sub tellName { my ($self) = $_[0]; return $self->{'name'}; } sub introduce { my ($self) = $_[0]; print "Hello, I'm ", $self->tellName(), "\n"; } } { package child; #person + ability to know parents our @ISA = qw(person); # inherits from person sub new { my ($class, $name, $mom, $dad) = @_; my $self = $class->SUPER::new($name); $self->{mom} = $mom; $self->{dad} = $dad; bless $self, $class; return $self; } sub introduce { my($self)=$_[0]; $self->SUPER::introduce(); for (qw/mom dad/) { if ($self->{$_}) { print "Here's my $_: ", $self->{$_}->tellName(); } } } } package main; my $mom = new person("Alice"); $mom->introduce(); # that time it works. print "\n"; my $son = new child("Fred", $mom); $son->introduce();

    The important thing to notice is that the child package is building on the provided definition of a person, adding to that person the ability to remember who its parents are. The packages themselves hold no data, only the objects will hold data. I think partly your use of default names is confusing the issue between class (the description) and the object (what is created using the description as a template). If your person class was able to call its own 'tellName' instead of the inherited one, then you would never have a way to override the behavior of tellName which is exactly the point of inheritance! ;) I hope this helps you.


    ___________
    Eric Hodges
Re^2: my $self is stumped!
by eric256 (Parson) on Jun 18, 2007 at 18:12 UTC

    BTW if you change that to:

    if ( ref($self) eq 'person'){ $self->tellName(); } if ( ref($self) eq 'child') { person::tellName($self);}
    It will then work as expected, though I still wouldn't recommend it because now you have no way to override the behavior of tellName.


    ___________
    Eric Hodges
Re^2: my $self is stumped!
by ysth (Canon) on Jun 19, 2007 at 22:20 UTC
    An additional puzzle: why doesn't this work?
    if ( ref($self) eq 'person') { $self->tellName(); } if ( ref($self) eq + 'child') {$self->SUPER::tellName();}
    Because perl looks at the code $self->SUPER::tellName(), and says, ah, you want to call the tellName method in the superclass of the current package. It doesn't take $self into account at all. To do that, you need to go beyond what perl itself provides and use something like SUPER or NEXT.