René Nyffenegger
René Nyffenegger

Reputation: 40499

How do I call the grandparent's constructor (because the parent's constructor is not defined)?

I believe, the canonical way to call the parent's class' constructor in Perl is:

package Child;
our @ISA = 'Parent';

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

However, this construct doesn't seem to work if Parent does not explicitely define a new function (but Grandparent does).

This is the case, for example, with Net::FTP::File.

tq84_ftp.pm:

package tq84_ftp;

use warnings;
use strict;

our @ISA = qw(Net::FTP::File);

sub new {
  my $class = shift;
  my $self = $class->SUPER::new('localhost')
     or die($@);
  return $self;
}    

1;

script.pl:

use tq84_ftp;
tq84_ftp->new();

Output:

Can't locate package Net::FTP::File for @tq84_ftp::ISA at tq84_ftp.pm line 10.
Can't locate package Net::FTP::File for @tq84_ftp::ISA at tq84_ftp.pm line 10.
Can't locate object method "new" via package "tq84_ftp" at tq84_ftp.pm line 10.

How do I specify that I want Perl to find the correct (here: grantparent's) new function?

Upvotes: 2

Views: 172

Answers (2)

Sinan Ünür
Sinan Ünür

Reputation: 118118

It seems you assume that Net::FTP::File is a subclass of Net::FTP and, therefore

my $self = $class->SUPER::new('localhost') ...

should invoke Net::FTP's new method.

However, in fact, Net::FTP::File does not inherit from Net::FTP. Instead, it redefines some methods in Net::FTP. Therefore, if your class inherits from Net::FTP::File, it will not be child of Net::FTP.

You can see this easily if you look at the source code for Net::FTP. Note that there is no use base 'Net::FTP' or use parent 'Net::FTP' or our @ISA = qw( Net::FTP ) below:

package Net::FTP::File;

use strict;
use warnings;
use Net::FTP;

# ...

sub Net::FTP::pretty_dir {
    shift;
    my $newp = shift;
    if ( defined $newp ) {
        $pretty = $newp;
        $DirProcHash{cols} = $cols{pretty}  if $pretty;
        $DirProcHash{cols} = $cols{utility} if !$pretty;
    }
    return $pretty;
}

# ...

sub Net::FTP::isfile {
    my $ftp = shift;
    return 1 if $ftp->exists(@_) && !$ftp->isdir(@_);
    0;
}

etc etc.

Upvotes: 5

ikegami
ikegami

Reputation: 385655

However, this construct doesn't seem to work if Parent does not explicitely define a new function (but Grandparent does).

Not true.

$ perl -E'
   package Grandparent {
      sub new { CORE::say(__PACKAGE__) }
   }

   package Parent {
      our @ISA = "Grandparent";
   }

   package Child {
      our @ISA = "Parent";
      sub new { my $class = shift; $class->SUPER::new(); }
   }

   Child->new();
'
Grandparent

Can't locate package Net::FTP::File

This a warning obtained when you try to inherit from a class that hasn't been declared. Specifically, you are trying to use Net::FTP::File without having loaded it.

Replace

our @ISA = 'Net::FTP::File';

with

use Net::FTP::File qw( );
our @ISA = 'Net::FTP::File';

or with

use parent 'Net::FTP::File';

Can't locate object method "new" via package "tq84_ftp"

This message is a bit unclear, but it's due to the fact that Net::FTP::File->new doesn't exist. Net::FTP::File isn't a class, much less a subclass of Net::FTP. It has no methods, much less a new method. It makes no sense to inherit from Net::FTP::File.

You appear to want to create a Net::FTP object, so replace

use parent 'Net::FTP::File';

with

use parent 'Net::FTP';

Finally, you want to load Net::FTP::File for the methods it adds to Net::FTP objects (which includes object of classes that inherit from Net::FTP). To do that, simply add

use Net::FTP::File qw( );

Upvotes: 6

Related Questions