john doe
john doe

Reputation: 403

Calling a known subclass function from superclass?

I don't know if this is possible, but I would like to call a known subclass function from Perl. I need something "generic" to call something more specific. My superclass is going to assume that all classes that subclass it have a known function defined. I guess this is similar to Java "implements".

For example let's say I have the following code:

GenericStory.pm

package Story::GenericStory;

sub new{
   my $class = shift;
   my $self = {};

   bless $self, class;
   return $self;
}

sub tellStory {
   my $self;

   #do common things
   print "Once upon a time ". $self->specifics();
}

#

Story1.pm

package Story::Story1;
use base qw ( Story::GenericStory );

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

   return $self;
}

sub specifics {
   my $self;
   print " there was a dragon\n";
}

#

Story2.pm

package Story::Story2;
use base qw ( Story::GenericStory );

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

   return $self;
}

sub specifics {
   print " there was a house\n";
}

#

MAIN

my $story1 = Story::Story1->new();
my $story2 = Story::Story2->new();

#Once upon a time there was a dragon.
$story1->tellStory();


#Once upon a time there was a house.
$story2->tellStory();

EDIT:

The code works fine. I simply forgot a "my $self = shift;" in tellStory();

Upvotes: 2

Views: 300

Answers (2)

amon
amon

Reputation: 57600

What you want is very much like a trait (or in Perl: a role).

Traits are a relatively recent addition to object oriented systems. They are like interfaces in that they can require an inheriting class to implement certain methods, but they are like a abstract superclass in that they can provide certain methods themselves.

The Moose object system allows roles. A class can be declared with a certain role. Here your example written with MooseX::Declare:

use MooseX::Declare;

role Story::StoryTeller{
    requires 'specifics';

    method tellStory() {
        print "Once upon a time ";
        $self->specifics();
    }
}

class Story::Story1 with Story::StoryTeller {
    method specifics() {
        print " there was a dragon\n";
    }
}

class Story::Story2 with Story::StoryTeller {
    method specifics() {
        print " there was a house\n";
    }
}

my $story1 = Story::Story1->new();
my $story2 = Story::Story2->new();

#Once upon a time there was a dragon.
$story1->tellStory();
#Once upon a time there was a house.
$story2->tellStory();

This isn't inheritance: $story1->isa("Story::StoryTeller") is false, but it does this role: $story1->DOES("Story::StoryTeller") is true.

For every class that DOES a certain role, an instance of that class can all methods of the role. Therefore, $story1->can("tellStory") is true, and in reverse for every Story::StoryTeller instance, $instance->can("specifics") will be true.

A role cannot be instantiated on its own.

Upvotes: 0

ysth
ysth

Reputation: 98398

Your code works fine as is (modulo trivial errors); you may want to add in the superclass:

sub specifics {
    require Carp;
    Carp::confess("subclass does not implement required interface");
}

or similar.

Upvotes: 5

Related Questions