What am I missing?
In short: main.pl
calls a subroutine (format_date
) by its unqualified name that's never been imported to it. (Further, the program doesn't even load the package in which that sub is defined.)
The problem is that the question mixes up notions of class and package. While Perl allows us to do so as the distinction is blurry,† we don't have to abuse it: your packages A
and A::B
aren't much of a class -- they cannot construct an instance (an object) as there is no sub that bless's a referent, and they don't use other object-oriented tools either (the indicated inheritance isn't used).
Then treating them as a class hierarchy bites: that inheritance established in the question doesn't import subs, as explained by tobyink.
The simplest way to fix this is to make your packages into normal classes and use them as such.
The program (main.pl
)
use warnings;
use strict;
use feature 'say';
use A::B;
my $obj = A::B->new;
my $string = $obj->format_date();
say $string;
File A.pm
package A;
use warnings;
use strict;
sub new { bless {}, shift } # make it a proper constructor...
sub format_date { return scalar localtime }
# other subroutines/methods in package A
1;
File A/B.pm
package A::B;
use warnings;
use strict;
use parent qw(A); # or, if you must: use base qw(A)
# other code in package B
1;
Now calling perl main.pl
prints the (local) date, Wed Jan 18 13:56:47 2023
.
Another way would be to have them as mere packages and to write A::B
so that it (explicitly) imports needed subs from A
, as they are requested. This is much more complicated and has no advantages over having classes.
See this SO page for more.
Alternatively, you could carry on the act and with the code you have actually treat A
and A::B
as classes, with A::B
inheriting from A
-- call format_date
as a class method.
So instead of my $string = format_date()
, use
my $string = A::B->format_date();
Now format_date
is taken as a class method and since it is not defined in A::B
the inheritance hierarchy is followed and it is found in A
. The package name (A::B
) is passed as the first argument and the method runs.
However, I wouldn't recommend this. Using packages both as classes and for exporting is complicated to get right, complex in use -- and there is no reason for it.
† A class is a package, firstly. See the reference perlobj and the tutorial perlootut.
For example, with an ordinary package, that never desired to be a class, we can call its subs as Packname->subname
-- and it will behave as a class method, where Packname
gets passed to subname
as the first argument.
But this is more of a side-effect of Perl's (intentionally) simple object-oriented system, that shouldn't be abused. I strongly recommend to not mix: don't push an exporting package to be used as a class (perhaps by slapping an OO feature to it, like inheritance), and don't EXPORT
from a class (a package intended for object-oriented use, that normally has a bless
-ing sub(s)).
See the footnote, and the preceding text, in this post, for more elaborate statements on class-vs-package in Perl.