Recipe 13.6 Cloning Constructors

13.6.1 Problem

You want to write a constructor method that might be invoked on an existing object, and if so, to use that object for default values.

13.6.2 Solution

Start your constructor like this:

my $proto  = shift;
my $class  = ref($proto) || $proto;
my $parent = ref($proto) && $proto;

The $class variable will contain the class to bless into, and the $parent variable will either be false, or else the object you're cloning.

13.6.3 Discussion

Sometimes you need another object of the same type as the current one. You could do this:

$ob1 = SomeClass->new( );
# later on
$ob2 = (ref $ob1)->new( );

but that's not very clear. It's clearer to have a single constructor that behaves correctly, regardless of whether its invocant is a class name or an existing object of that class. As a class method, it should return a new object with the default initialization. As an instance method, it should return a new object initialized from the object it was invoked on:

$ob1 = Widget->new( );
$ob2 = $ob1->new( );

Here's a version of new that takes this into consideration:

sub new {
    my $proto  = shift;
    my $class  = ref($proto) || $proto;
    my $parent = ref($proto) && $proto;

    my $self;
    # check whether we're shadowing a new from @ISA
    if (@ISA && $proto->SUPER::can("new") ) {
        $self = $proto->SUPER::new(@_);
    } else {
        $self = {  };
        bless ($self, $class);

    $self->{PARENT}  = $parent;
    $self->{START}   = time( );   # init data fields
    $self->{AGE}     = 0;

    return $self;

Initializing doesn't have to mean simply copying values from the parent. If you're writing a linked list or binary tree class, your constructor can return a new object linked into the list or tree, when invoked as an instance method.

13.6.4 See Also

perlobj(1) and Chapter 12 of Programming Perl; Recipe 13.1; Recipe 13.10; Recipe 13.13