I am just a beginner with perl and trying to wrap my head around objects. I am having no problem creating a object, however, I am having issues when I introduce a child class (sorry if wrong terminology) and exporting everything to the main:: script. When I say everything essentially I mean the subroutines (not methods) I want exported from the parent .pm. See code below.
#main.pl
use A::B;
my $string = format_date();
#A.pm
package A;
use strict;
use Exporter qw(import);
our @EXPORT = qw(format_date);
sub format_date { #do stuff}
#other subroutines/methods in package A
#B.pm -> located in A/B.pm
package A::B;
use strict;
use base qw(A);
other code in package B
I was expecting the 'use A::B;' syntax to load the format_date subroutine to the main:: script. When I run it I get - Undefined subroutine &main::format_date called at.....
When I use 'use A;' in main.pl everything runs fine.
What am I missing?
Note - some of our stations use 5.8.8 so some syntax needs to be slightly older, like the use base. Most use 5.34, but not all.
CodePudding user response:
Subclasses inherit methods defined in parent classes, but don't automatically import subs from parent classes. (Inheritance is more a run-time feature, and importing is more a compile-time feature.)
Generally speaking, if you're trying to use object-oriented features to write a module (like using inheritance, defining methods, a constructor, a destructor, etc) and the module is also an exporter, then you probably want to step back to the design phase. Consider splitting it into two separate modules: an object-oriented one and a function exporter.
(It certainly is possible to write modules that do both, but in most cases, it's an sign that you've got a confused design.)
CodePudding user response:
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 as they cannot construct an instance (an object); there is no sub that bless's a referent.
Then treating them as a class hierarchy bites: that formal inheritance used 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.
† 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.
However, this is more of a side-effect of Perl's simple structure of the object-oriented system, that shouldn't be abused. I strongly recommend to not mix: don't treat a package (that doesn't bless
and is not meant to be a class) as a class and don't EXPORT
from a class.