spoonervt has asked for the wisdom of the Perl Monks concerning the following question:

I know that exporting variables/functions is bad style possibly leading to collisions, but I expected it to work.

I have a scenario where I am placing a package (w.pm) in a subdirectory and when doing so the export/import seems to fail.

when I load the package with:

 use w;  # the package lives in one of the directories in @INC

everything works as expected -> exported variables and functions are available in (and pollute) main's namespace.

When I load the package with:  use A::w; # ./A is not in @INC the package loads fine (the BEGIN{} startup message is issued) and I can use variables/functions when specifying the package name with w::, but not without it.

Am I misreading how to use Exporter, @EXPORT, or is my understanding of how to create packages in a folder hierarchy wrong?

Any insight is appreciated.

-Steffen (using v5.8.8)

main:

#!/tool/pandora64/bin/perl -w -I ./ use strict; use warnings; use v; # variables/funcs work without v::, the package code is a +lmost the same) #use w; # This makes variables/funcs work without w:: use A::w; # this requires w:: to identify the package sub_in_v(); w::sub_in_w(); $var_in_v = "v-variable"; $w::var_in_w = "w-variable"; # works only because of the w:: when use- +ing A::w printf("%s\n", $var_in_v); printf("%s\n", $w::var_in_w); # works only because of the w:: when us +e-ing A::w print(join("\n", @INC)); 1;
package w:
package w; # in ./A use Data::Dumper; use Exporter; our $var_in_w; our @EXPORT= ('$var_in_w', 'sub_in_w'); our @ISA = qw(Exporter); sub sub_in_w{ print("this is from a sub in package SRAM::w!\n"); } BEGIN{ print('this is w\'s BEGIN, @ISA = ', Dumper @ISA, "\n"); 1; } END{ print("w ending now.\n"); } 1;

Replies are listed 'Best First'.
Re: variable import from package fails even though package apparently loads
by ikegami (Patriarch) on Jan 04, 2025 at 05:53 UTC

    Three things need to match:

    • The name provided to use or require.
    • The path to the file relative to a directory in @INC.
    • The namespace provided to package.

    In your working version, you have

    • use w;
    • w.pm (relative to . in @INC)
    • package w;

    They match, so all's good.

    This is what happens:

    use w; loads w.pm, then checks if the w namespace provides a method named import. If it does, the method is called.

    The module asks Exporter to provide this method and to export $var_in_w and sub_in_w when called (with no additional arguments). $var_in_w and sub_in_w are therefore exported.


    In your broken version, you have

    • use A::w;
    • A/w.pm (relative to . in @INC)
    • package w;

    The package directive doesn't match the other two, so problems are to be expected.

    This is what happens:

    use A::w; loads A/w.pm, then checks if the A::w namespace provides a method named import. If it does, the method is called.

    The A::w namespace doesn't provide an import method. Nothing exports $var_in_w and sub_in_w.


    If the file is to remain at A/w.pm relative to the script's dir,

    • Possible fix #1

      • -I . (buggy) or use FindBin qw( $RealBin ); use lib $RealBin; (correct)[1]
      • use A::w;
      • A/w.pm (relative to . or $RealBin in @INC)
      • package A::w;
    • Possible fix #2

      • -I A (buggy) or use FindBin qw( $RealBin ); use lib "$RealBin/A"; (correct)[1]
      • use w;
      • w.pm (relative to A or $RealBin/A in @INC)
      • package w;

    The choice of fix will come down to this question: Is the module named A::w (fix #1), or is it named w and happens to be in a directory named A (fix #2)?

    For example, one might organize their project as follows:

    • scripts/
      • script.pl
    • lib/
      • Foo/
        • Bar.pm

    This could be coded as follows:

    scripts/script.pl
    use FindBin qw( $RealBin ); use lib "$RealBin/../lib"; use Foo::Bar; ...
    lib/Foo/Bar.pm
    package Foo::Bar; ...

    1. $RealBin is the directory that contains the script. . is the current work directory, which has nothing to do with the directory that contains the script. If they happen to be the same, it's just a coincidence.

    Update: Many tweaks to presentation.

      Thank you for the explanation. I somehow missed the fact that I needed to replicate the directory hierarchy path in the package declaration.
Re: variable import from package fails even though package apparently loads
by Paladin (Vicar) on Jan 04, 2025 at 03:38 UTC
    If you are going to use A::w;, your package has to also be package A::w; inside the file w.pm in the A directory.