Search code examples
perlautoload

Why doesn't my package export names in `@EXPORT`?


I'm tying to provide some special constants via the autoload function. Basically creating the functions works fine, but the code would allow to create any name for the constants instead of a specific allowed set.

So I tried limiting the names by exporting them from the generating package.

Unfortunately the package exports noting at all, and I don't see the error.

The demonstration code is this:

#!/usr/bin/perl
use warnings;
use strict;

# Tell Perl module is loaded already (fake)
sub UNIVERSAL::_fake_load($)
{
    my $pkg = $_[0];

    # Tell Perl module is loaded already
    $INC{join('/', split(/::/, $pkg)) . '.pm'} = 1;
}

package MAGIC_STUFF;

our (@EXPORT, @ISA, $VERSION);

BEGIN {
    use Exporter;
    $Exporter::Verbose = 1;
    $VERSION = 'v0.0.0';                # for version checking
    @ISA = qw(Exporter);
    @EXPORT = qw(abra ka dabra);        # exported by default
}

use AutoLoader;

sub AUTOLOAD {
    use vars qw($AUTOLOAD);
    my ($sub_name, @args) = ($AUTOLOAD, @_);
    no strict 'refs';

    *$sub_name = sub { "$sub_name defined for (" . join(',', @args). ")" };
    goto &$sub_name;                    # return from AUTOLOAD
}

sub import
{
    print "import: ", join(' ', @_), "\n";
    Exporter::import(@_);
}

BEGIN {
    $DB::single = 1;
    foreach (@EXPORT) {
        eval "sub $_;";
    }
    __PACKAGE__->_fake_load();
}

1;

package main;


use MAGIC_STUFF;
#MAGIC_STUFF->import(1,2,3);

print MAGIC_STUFF::joe(7), "\n";
print ka(3), "\n";

When debugging it, I see this essentially:

> perl -d test.pl

Loading DB routines from perl5db.pl version 1.39_10
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

MAGIC_STUFF::CODE(0x16d17b0)(test.pl:45):
45:         foreach (@EXPORT) {
#...
  DB<1> n
MAGIC_STUFF::CODE(0x16d17b0)(test.pl:46):
46:             eval "sub $_;";
  DB<1> n
MAGIC_STUFF::CODE(0x16d17b0)(test.pl:46):
46:             eval "sub $_;";
  DB<1> n
MAGIC_STUFF::CODE(0x16d17b0)(test.pl:46):
46:             eval "sub $_;";
  DB<1> n
MAGIC_STUFF::CODE(0x16d17b0)(test.pl:48):
48:         __PACKAGE__->_fake_load();
  DB<1> n
import: MAGIC_STUFF
Importing into MAGIC_STUFF from MAGIC_STUFF: abra, dabra, ka at test.pl line 40.
        MAGIC_STUFF::import('MAGIC_STUFF') called at test.pl line 56
        main::BEGIN() called at test.pl line 56
        eval {...} called at test.pl line 56
MAGIC_STUFF::(test.pl:16):      our (@EXPORT, @ISA, $VERSION);
  DB<1> n
MAGIC_STUFF::(test.pl:51):      1;
  DB<1> n
main::(test.pl:59):     print MAGIC_STUFF::joe(7), "\n";
  DB<1> n
MAGIC_STUFF::joe defined for (7)
main::(test.pl:60):     print ka(3), "\n";
  DB<1>
Undefined subroutine &main::ka called at test.pl line 60.
 at test.pl line 60.
Debugged program terminated.  Use q to quit or R to restart,

The foreachloop was an attempt to fix the problem, but it did not help.

What confuses me most is

Importing into MAGIC_STUFF from MAGIC_STUFF

Shouldn't it import into main?


Solution

  • Exporter::import exports to its caller's namespace. The caller is MAGIC_STUFF::import, so you're exporting to the MAGIC_STUFF namespace.

    A simple fix is to use goto to remove MAGIC_STUFF::import from the call stack. The caller of MAGIC_STUFF::import thus becomes the caller of Exporter::import. (@_ is provided unchanged to new sub.)

    sub import
    {
        print "import: ", join(' ', @_), "\n";
        goto &Exporter::import;
    }