Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invocation of SUPER::new()

I've seen two ways to implement the new method in a derived class.

Method one:

sub new {
    my $invocant = shift;
    my $class   = ref($invocant) || $invocant; 
    my $self = {};
    bless($self, $class);
    $self = $self->SUPER::new( @_ );
    return($self);
}

Method two:

sub new {
  my $self = shift;
  my $class = ref($self) || $self;
  return $self if ref $self;
  my $base_object = $class->SUPER::new(@_);
  return bless ($base_object, $class);
}

I'm not sure I understand what the difference is. Can anyone please explain?


From your comments and answers I can see that the ref() part is bad.

But what about the use of SUPER::new(@_)? In the first example, the hashref is blessed into the derived class and then that object's SUPER's new is called and saved into the same object.

In the second example on the other hand, a base object is created from the class's SUPERs new method and that is blessed into the new class.

What is the difference between these two ways? It looks like the first overwrites the object with the base object. The second seems to "double-bless". I'm confused.

like image 470
simbabque Avatar asked Jun 08 '12 14:06

simbabque


2 Answers

Why not just:

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

-- with the only exception for the deepest base class in the hierarchy which should call either bless $self, $class; or maybe my $self = fields::new($class); in case you use fields.

like image 68
Dallaylaen Avatar answered Oct 19 '22 20:10

Dallaylaen


Update

You ask:

What is the difference between these two ways? It looks like the first overwrites the object with the base object. The second seems to "double-bless". I'm confused.

Take heart. Each of the two methods you show is itself confused, and neither should be emulated.

Method one blesses an object of class DerivedClass into existence and then uses that object to call the allocator/constructor of some AncestorClass, replacing itself. Now, AncestorClass::new probably also uses the unfortunate ref($yuck) || $yuck idiom, which means that the new object will be blessed into DerivedClass. So, one DerivedClass object is used to construct another to replace it. Dubious.

Method two returns its receiver ($self) if the receiver is an object. (Note that ref($self) is checked twice when it need only be checked once.) That is, $o->new() returns the very same $o under method two. If the receiver is not an object but a class name, that is, if instead we had called DerivedClass->new, then AncestorClass::new is called. But the first argument to the superclass' method is 'DerivedClass', and presumably the superclass does not hardcode its blessed package name, so the subsequent re-blessing is pointless.

Just don't worry about these examples. Instead please consult perlobj and perlootut for safe and sane uses of SUPER.

Original answer

Augh, my eyes!

Method one is, as daxim commented, an objectionable means of allowing one to construct an object from the same class as an existing object:

my $o1 = MethodOne->new();
my $o2 = $o1->new();        # $o2 is a clone of $o1.  No, wait, it isn't!
                            # It's a brand new, "empty" object.  Ha,
                            # fooled you.

Method two is (I think) a workaround to this confusing practice. Your method two will return the very same object if new() is called.

my $o1 = MethodTwo->new();
my $o2 = $o1->new();         # $o2 is a new MethodTwo.  No, wait, it isn't!
                             # It's a brand new object.  No, wait, it isn't!
                             # It's a /exactly the same object/ as $o1.  Ha,
                             # fooled you.

Don't use either. :) There may be some applications where either of the above semantics make perfect sense. I just wouldn't name that method new() in those applications...

like image 34
pilcrow Avatar answered Oct 19 '22 19:10

pilcrow