Is there an actual derived class at runtime in Perl?
Asked Answered
H

1

7

I am looking into Perl OO (new to Perl). I created a trivial example hierarchy:
Parent class:

#!usr/bin/perl  
use strict;  
use warnings;  

package Objs::Employee;  

my $started;  

sub new {  
    my ($class) = @_;  
    my $cur_time = localtime;  
    my $self = {  
        started => $cur_time,  
    };
    print "Time: $cur_time \n";  
    bless $self;  
}  

sub get_started {  
    my ($class) = @_;  
    return $class->{started};  
}  

sub set_started {  
    my ($class, $value) = @_;  
    $class->{started} = $value;  
}  

1;  

Child class:

#!/usr/bin/perl  
package Objs::Manager;  
use strict;  
use warnings;  

use base qw (Objs::Employee);  

my $full_name;  

sub new {  
    my ($class, $name) = @_;  
    my $self = $class->SUPER::new();  
    $self->{full_name} = $name;  
    return $self;     
}  

1;  

I try to test it as follows:

#!/usr/bin/perl  
use strict;  
use warnings;  


use Objs::Manager;  

my $emp = Objs::Manager->new('John Smith');  
use Data::Dumper;  
print Dumper($emp); 

Result:

Time: Sun Sep 29 12:56:29 2013

$VAR1 = bless( {
                 'started' => 'Sun Sep 29 12:56:29 2013',
                 'full_name' => 'John Smith'
               }, 'Objs::Employee' );

Question: Why is the object reported in the dump an Obj::Employee and not an Obj::Manager?
I called new on a Manager.

Hippy answered 29/9, 2013 at 11:4 Comment(2)
By the way, since the methods get_started and set_started are instance methods (unlike new which is a class method), the first argument to them will be an instance of the class, not the class itself. So you should call it $self or something to avoid confusion.Portauprince
The $started package variable in Objs::Employee is unused.Disconsolate
S
11

Always use two arguments for bless, as $class tells into which package should object be blessed. If $class is omitted, the current package is used.

bless $self, $class; 

output

$VAR1 = bless( {
             'started' => 'Sun Sep 29 13:24:26 2013',
             'full_name' => 'John Smith'
           }, 'Objs::Manager' );

From perldoc -f bless:

Always use the two-argument version if a derived class might inherit the function doing the blessing

Solent answered 29/9, 2013 at 11:23 Comment(4)
Why?Could you please elaborate?Hippy
In my example the $class is a passed-in argument which I would expect to be Manager since I did: Objs::Manager->new. So the $self but itself is what the super constructor returns which is an Employee and the bless downcasts it?Hippy
Class is always first parameter in constructor (static method). When called from child then child class is passed, otherwise it is current class. Note that $class inside your child and parent are different variables having different values.Solent
Even if $class is Objs::Manager in the call to Objs::Employee->new (which I'm not disputing), it's a moot point because you haven't used $class anyway. But because you haven't used the second argument to bless, it defaults to the current package, which is set by the line package Objs::Employee;.Portauprince

© 2022 - 2024 — McMap. All rights reserved.