perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

I was getting an error in one of my progs and distilled the problem. I only tested it on 5.16 and 5.20, but I don't remember any changes in more recent perls that might indicate it's fixed.
# # note: may need to install "mem" ("cpan -i mem") # use strict; use warnings; ###################################################################### +########## { package Fields; use strict; use warnings; use mem; our (@flds, @EXPORT); @EXPORT=qw(@flds); use Exporter 'import'; } ###################################################################### +########## package main; use strict; use warnings; use Fields; my $nfld = scalar @flds;

I get error:

> perl t02-array.t Global symbol "@flds" requires explicit package name at t02-array.t li +ne 19. Execution of t02-array.t aborted due to compilation errors.
If I put qw(@flds) after the use Fields, I get:
"@flds" is not exported by the Fields module
I think I'm missing something obvious.... :-(.

Thanks...
-Linda

Replies are listed 'Best First'.
Re: Why is @flds not imported?
by ikegami (Patriarch) on Sep 24, 2017 at 23:14 UTC

    You gotta be super careful when you place a module in a script or in the same file as another module. It's very easy to execute code in the wrong order. And this is what happened here.

    Let's look at the following simplified version of your code:

    { package Fields; our (@flds, @EXPORT); @EXPORT=qw(@flds); use Exporter 'import'; } package main; use Fields; my $nfld = scalar @flds;

    In broad strokes, the following is the compilation and execution process:

    1. Script's compilation phase:
      1. our (@flds, @EXPORT) is compiled.
      2. @EXPORT=qw(@flds) is compiled.
      3. use Exporter 'import'; is compiled:
        1. require Exporter; is executed:
          1. [Exporter.pm's compilation phase happens here]
          2. [Exporter.pm's runtime phase happens here]
        2. import Exporter 'import'; is executed.
      4. use Fields; is compiled:
        1. require Fields; is executed.
        2. import Fields; is executed. ⇐
      5. my $nfld = scalar @flds; is compiled.
    2. Script's runtime phase:
      1. our (@flds, @EXPORT) is executed.
      2. @EXPORT=qw(@flds) is executed. ⇐
      3. my $nfld = scalar @flds; is executed.

    Note the relative order of the statements in bold. At the time of import, @EXPORT was empty.

    Fix:

    BEGIN { package Fields; use strict; use warnings; use mem; our (@flds, @EXPORT); @EXPORT=qw(@flds); use Exporter 'import'; $INC{"Fields.pm"} = 1; } { # <-- Not necessary, but enforces cleaner code. use strict; use warnings; use Fields; my $nfld = scalar @flds; }
      What really puzzled me, is why the require in use Fields is not throwing an error.

      And changing the name did indeed show a conflict. Turns out that the pragma fields (lowercase) comes with a bundled "class" (or whatever) Fields (capitalized) which is used.

      C:\Windows\system32>corelist fields Data for 2013-01-20 fields was first released with perl 5.005 C:\Windows\system32>perldoc Fields NAME fields - compile-time class fields SYNOPSIS ...

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

        Why should 'use Fields' throw an error? It's included in the file.

        The copy of Fields in memory will have priority over the disk version with 'use mem'.

        Edit: Oh -- you are not talking about my version... nevermind.

      You gotta be super careful when you place a module in a script or in the same file as another module. It's very easy to execute code in the wrong order. And this is what happened here.
      Unfortunately, it's not an 'order' thing as it's not the problem anon-monk suggested it was. :-(

      I trimmed away too much for the "simplified case" and didn't notice when I oversimplified it because it gave the same error message (even when I had code in the BEGIN phase). *sigh*

      So it's back to the drawing board.

      Edit Didn't have to go far...seems to have something to do with whether or not another package using the same module (Fields) is present AND my own export routine. I suspected it was in my own export code, but when I substituted the standard Exporter I got the same error -- but only because I'd already removed the 'BEGIN' code.

      If you're interested, when I figure out the problem, I can update things here, but it's likely some boring error where I missed something simple. ;-)

      -l

Re: Why is @flds not imported?
by Anonymous Monk on Sep 24, 2017 at 22:03 UTC
    it's a compile time vs runtime thing, "use Fields" happens at compile time, but "@EXPORT=qw(@flds)" doesn't happen until runtime, put it in a BEGIN and it works
      Well this is annoying. In my original code that I cut down to a "minimal case", I had the assignment to @EXPORT, effectively, in a BEGIN. with another function (and w/different names). I.e.:
      use mem(@EXPORT=qw(@xmission_flds TorFldN)); #... sub TorFldN(;$) { #... }
      References to the function worked as expected, but not the array. FWIW, substituting in use mem(...) also makes the error go away in the reduced-test case, but since that's what was in the original that's not the problem in the original. I'll have to try minimizing it again, but it's more than a bit of a pain as the original is 823 lines long. While I have no problem posting a sanitized version of the original, it references several modules not on CPAN, as well as just being long.

      I'll have to go back to original and try cutting it down again...sigh... unfortunately, this is the problem in "cutting things down" -- I ended up cutting away so much that the original problem goes away and I don't even notice it...

      *sigh*.

      -l

Re: Why is @flds not imported?
by huck (Prior) on Sep 24, 2017 at 22:00 UTC

    I am not a modules expert by any means, but all mine include

    our @ISA= qw( Exporter );

      Yeah, it makes no sense to inherit from Exporter, so

      use Exporter qw( import );

      was added as an alternative to

      use Exporter qw( ); push our @ISA, qw( Exporter );

      back in 2004.

      "use Exporter 'import';" is good enough