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

I have a test case for my issue, and a real case. In the real case I have a dbg module I use to manage my debug code. And I have a libs module that has various useful subs. The dbg module calls some of the procs in the libs, and most of the libs procs call dbg procs at some point. Kinda a loop, but it is all good, as I have code to detect looping cases and act appropriately. Anyway, to make it more interesting, several procs from dbg are exported with @EXPORT (yes not with EXPORT_OK). None of the libs stuff is exported. The issue comes when I have a script that uses the dbg but not the libs. When that happens, and the script calls a sub in dbg that calls a sub in libs that calls a different sub in dbg, then the libs sub can't find the exported dbg sub. Now the libs module does use dbg, and the dbg does use libs. But it seems that the export doesn't happen for the libs module in this case... However if I write a script that just uses the libs module and not the dbg, then the export of dbg subs to libs does work...

so here is the test case code, module L represents libs, module Z represents the dbg module.
it.pl
use strict; use Z; print "hey 1\n"; zProc(); subzProc(); print "hey 2\n";
L.pm
package L; use strict; use Exporter; our (@ISA) = qw(Exporter); use Z; sub lProc { print "I am lProc\n"; } sub sublProc { print "I am sublProc\n"; zProc(); }
Z.pm
package Z; use strict; use Exporter; use L; our (@EXPORT) = qw(zProc subzProc); our (@ISA) = qw(Exporter); sub zProc { print "I am zProc\n"; } sub subzProc { print "I am subzProc\n"; L::lProc(); L::sublProc(); } 1;

perl version is v5.8.5

The output is hey 1 I am zProc I am subzProc I am lProc I am sublProc Undefined subroutine &L::zProc called at L.pm line 22.

So in sub sublProc, the call to zProc doesn't work, cause the import/export didn't happen.

I do know a few workarounds, none of which are what I would like to do, and I would really like to know what is happening under the hood to cause this, as well as any possible solutions...

workarounds:
in it.pl if I use L before I use Z then it works... if after, doesn't work... (this is undesirable of course since it should not be a requirement for the end script to use L just to use Z...)
in L.pm I can simply not rely on the export and simply put the module name and :: in front of all calls to Z in L. This is undesirable cause I actually intend for other people to write scripts using these modules (all people in my team) and most people do the copy other code method of programing, and would likely copy some of the L code as starters for things, and thus the end code would be a mix of using the module name and not. That said, this is my top solution at the moment for lack of a better one...

so... any wisdom from the gurus on this would be great... I have poked around the web and found some mention of funky things...
http://perldoc.perl.org/Exporter.html under the heading Playing Safe mentions a caveat, but doesn't explain it. It also mentions a solution of using a begin block, but that failed to work.

Thanks in advance for your time and thoughts...

Randell

Replies are listed 'Best First'.
Re: repeated use of module and EXPORT
by shmem (Chancellor) on May 23, 2008 at 16:12 UTC

    Z uses L, so L is compiled and executed before the body of Z is even parsed. At compilation of L the assignment to @EXPORT in package Z hasn't been executed, so tough noogies - L doesn't get sub zProc, since that isn't there yet... Exporter's import (which is what's executed in Z at Z->import() ) sees an empty @EXPORT.

    Use a BEGIN block to execute the assignment before compiling L via use:

    package Z; use strict; use Exporter; BEGIN { our (@EXPORT) = qw(zProc subzProc); our (@ISA) = qw(Exporter); } use L; sub zProc { print "I am zProc\n"; } sub subzProc { print "I am subzProc\n"; L::lProc(); L::sublProc(); } 1;

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      wow... you are right... that does work...
      I had tried something very similar but I had the use L above the begin... I didn't think the location of the BEGIN would matter...
      So... I am guessing that use statments are just like BEGIN blocks and thus happen in the order they are encoutnered.. is that right?
        actually... how is compilation order determined... or do you have any good links to documentation about compilation order and such... I tried to find it, but most links where about compilers that make exe's out of your perl... Randell
Re: repeated use of module and EXPORT
by Anonymous Monk on May 23, 2008 at 15:47 UTC
    Don't do that. Either Z requires L or L requires Z, one or the other, never both.

      Why not? Happens all the time. My love and I require each other in any load order; that's just fine.

      What matters in mutual including is the state of the including module - it is not yet compiled in its entirety. If the included module relies on data structures of the including module which will be set up at run time in there, it won't get those. So, each module must be set up proper to be used by the other one, then use the other one.

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      That is a common statement to not have each use the other... but there is nothing wrong with doing so... and in this case it makes good sense... In the real case, libs and dbg... I would have to copy various libs subs into the dbg module to avoid the loop. which would cause duplication of code, which is also a never do... And since the two modules come together it is okay for them to rely on each other.
      in a certain sense, dbg is like a class that is being inherited, and libs is just a general module of subs to be used by anyone. So for them to be interdependent isn't really a problem for the design...

        How about having a third package, let's call it util, that contains the shared code. Include util in both libs and dbg, and you no longer have the loop.

        --MidLifeXis

        Yes there is - you don't know how to make it work. Listen to MidLifeXis suggeststion, and put the common functions in a another module.
Re: repeated use of module and EXPORT
by almut (Canon) on May 23, 2008 at 15:31 UTC

    Maybe you should use Z; instead of require "Z.pm"; in package L  (require does not call import(), like use does).

    Update: ah, sorry, overlooked that explicit call of Z->import(); ...

      yeah, that was a try at fixing it... I tried switching the use to a require and import, but that didn't work... the original test had just the use. I actually went a bit further, and defined my own import in Z and put some output in it, and found that it wasn't even being called when L uses Z. So then I had tried using require and calling import... no luck there either...