Search code examples
perlperl-exporter

Perl Exporter use variables from @EXPORT_OK in a subclass


I have looked for the last few hours and I am stumped.

I did see How can I share variables between a base class and subclass in Perl? but it does not answer my question

I am trying to write a utility module (testing purposes at this point) for use in internally developed scripts. But I seem to be having a tough go at getting exporter to actually export what I need it to.

What I have is below:

lib/Internal.pm:

package Internal;

use     5.008_008;
use     strict;
use     warnings;
use     Exporter;

our $VERSION = 1;
our @EXPORT_OK = qw($EMPTY $NOW);
our %EXPORT_TAGS = ( ':all' => \@EXPORT_OK );

our $EMPTY = q{};
our $NOW = time;

1;

lib/Internal/Utility.pm:

package Internal::Utility;

use     5.008_008;
use     strict;
use     warnings;
use     FindBin::libs;
use     parent qw(Internal);
use     Data::Dumper;

our $VERSION = 1;
our @EXPORT_OK = qw(run);
our %EXPORT_TAGS = ( ':all' => \@EXPORT_OK );

sub run
{
    print Dumper $NOW;
    print Dumper $EMPTY;
    exit;
}

1;

bin/test.pl:

#!/usr/bin/env perl

use     5.008_008;
use     strict;
use     warnings;
use     FindBin::libs;
use     Internal::Utility qw(:all);

run();
exit;

When I run the test.pl, I get the below error:

Global symbol "$NOW" requires explicit package name at lib/Internal/Utility.pm line 8.
Global symbol "$EMPTY" requires explicit package name at lib/Internal/Utility.pm line 9.
Compilation failed in require at ./test.pl line 7.
BEGIN failed--compilation aborted at ./test.pl line 7.

Why is the use parent in Internal::Utility not importing the variables from Internal.pm? Is there a way to tell use parent to explicitly import some variable?


Solution

  • In Perl, inheritance only affects how method calls are resolved. Everything else – variables, subroutines, and so on – remains just the same.

    That means you should import those symbols into your derived class, just like you'd import from any other module:

    package Internal::Utility;
    ...
    use Internal ':all';
    use parent qw(Internal);
    ...
    

    Perl uses packages as its sole namespacing mechanisms, but packages can also be used as classes. This can be a bit confusing. As a general advice, you should never mix those two: a package should EITHER offer an object-oriented interface OR an exporter-based, procedural interface. Mixing the two tends to result in misleading designs.