http://www.perlmonks.org?node_id=1022639

perlbaski has asked for the wisdom of the Perl Monks concerning the following question:

I have a parent class from which two I derive two child classes. The new () of both the child classes call parent class constructor.
package superModule; my $self; sub new(){ my $class=shift; my %params=@_; $self=(bless({"dbh"=>$params{"DB"}},$class)); return $self; } sub printSuper(){ print "Super module:".$self->{dbh}."\n"; } package myModule; @ISA=(superModule); my $self; sub new(){ my $class=shift; %params=@_; my $parentObj=superModule->new(%params); $self=(bless({"file_name"=>$params{"file name"}},$class)); $self->{"parent"}=$parentObj; return $self; } sub printFile(){ print "My file name from file obj ".$self->{file_name}."\n"; } package yourModule; @ISA=(superModule); my $self; sub new(){ my $class=shift; %params=@_; my $parentObj=superModule->new(%params); $self=bless({"block_name"=>$params{"block name"}},$class); $self->{"parent"}=$parentObj; return $self; } sub printBlock(){ print "My Block name from block obj ".$self->{block_name}."\n"; } return 1; use myModule; use yourModule; my %f_params=(DB=>"File DB value","file name"=>"Lisa"); my %b_params=(DB=>"Block DB vlaue","block name"=>"Pisa"); my $file_obj=myModule->new(%f_params); my $block_obj=yourModule->new(%b_params); $file_obj->printSuper(); $file_obj->printFile(); $block_obj->printSuper(); $block_obj->printBlock();
I see that Super module's dbh value is over written by yourModule input parameters. I see the problem self is getting overwritten, but is there a way I can keep the parent class variables separate in the two child class objects.

Replies are listed 'Best First'.
Re: Variables in Common parent class
by Athanasius (Archbishop) on Mar 10, 2013 at 03:58 UTC

    Some problems with the code shown:

    • $self is a class variable, it should be an object (instance) variable.
    • Subroutines have unneccessary prototypes.
    • use strict and use warnings are missing.
    • Module names should be capitalised.

    But the main problem is the structural relationship of the child classes to the parent class. Here is one way to do what is wanted:

    #! perl use strict; use warnings; #--------------------------------------------------------------------- +--------- { package SuperModule; sub new { my ($class, %params) = @_; my $self = { dbh => $params{DB} }; return bless $self, $class; } sub print_super { my ($self) = @_; print 'Super module: ', $self->{dbh}, "\n"; } } #--------------------------------------------------------------------- +--------- { package MyModule; our @ISA = qw( SuperModule ); sub new { my ($class, %params) = @_; my $self = SuperModule::new($class, %params); $self->{file_name} = $params{'file name'}; return bless $self, $class; } sub print_file { my ($self) = @_; print 'My file name from file obj ', $self->{file_name}, "\n"; } } #--------------------------------------------------------------------- +--------- { package YourModule; our @ISA = qw( SuperModule ); sub new { my ($class, %params) = @_; my $self = SuperModule::new($class, %params); $self->{block_name} = $params{'block name'}; return bless $self, $class; } sub print_block { my ($self) = @_; print 'My block name from block obj ', $self->{block_name}, "\ +n"; } } #--------------------------------------------------------------------- +--------- my %f_params = ( DB => 'File DB value', 'file name' => 'Lisa', ); my %b_params = ( DB => 'Block DB value', 'block name' => 'Pisa', ); my $file_obj = MyModule ->new(%f_params); my $block_obj = YourModule->new(%b_params); $file_obj ->print_super(); $file_obj ->print_file(); $block_obj->print_super(); $block_obj->print_block();

    Output:

    13:56 >perl 567_SoPW.pl Super module: File DB value My file name from file obj Lisa Super module: Block DB value My block name from block obj Pisa 13:56 >

    Hope that helps,

    Update: ++tobyink, below, for the improvements to the child class constructors.

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      All generally good advice, but for the constructors in the children, I'd prefer:

      sub new { my ($class, %params) = @_; my $self = $class->SUPER::new(%params); $self->{block_name} = $params{'block name'}; return $self; }

      This ensures that the parent constructor is called as a method (and thus obeys inheritance).

      There's no need to re-bless $self.

      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      Thanks! But one further question, why is there a dereferncing(->) operator while calling new on MyModule and scope resolution operator while calling new on SuperModule.

        With the scope resolution operator, you get a normal subroutine call. But with the dereferencing operator, you get a method call in which the name of the class is passed implicitly as the first argument. So

        Foo::bar(1, 2, 3);

        calls sub bar in the Foo package and passes 1, 2, 3 as the arguments (which are aliased in @_). But

        Foo->bar(1, 2, 3);

        calls Foo::bar with the arguments Foo, 1, 2, 3. Likewise, if $obj is of class Foo, then

        $obj->bar(1, 2, 3);

        calls Foo::bar with the arguments Foo, 1, 2, 3.

        See Methods in perlootut and Method Invocation in perlobj.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      I tried your program after moving the package code to different files, error from MyModule says undefined subroutine at SuperModule::new. Works only if SuperModule and MyModule are in same file.

      How can I make it see the new from SuperModule.pm?

        Organise the code like this:

        File main.pl:

        #! perl use strict; use warnings; use MyModule; use YourModule; # ... as before ...

        File SuperModule.pm:

        #! perl package SuperModule; # ... as before ... 1;

        File MyModule.pm:

        #! perl package MyModule; use strict; use warnings; use SuperModule; our @ISA = qw( SuperModule ); # ... as before ... 1;

        File YourModule.pm:

        #! perl package YourModule; use strict; use warnings; use SuperModule; our @ISA = qw( SuperModule ); # ... as before ... 1;

        Note that a standalone module (i.e., a file with a .pm extension) must return true on success. Hence the common practice of ending each module with 1; on a line by itself. See Perl Modules in perlmod.

        This scheme assumes that the four files are in the same directory. If they’re not, you will need to investigate the use lib pragma. See lib.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,