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

Dear Monks,

I am facing some problems in compiling two modules which use one another and one of the module imports few methods exported by the other. You can find both modules below:

=========================================
package First;

use strict;
use warnings;

BEGIN {
     print "Start compiling First\n";
}
BEGIN {
     print "Before using Second in First\n";
}

# Using Second before we export any method
use Second;

BEGIN {
     print "Just used Second in Data\n";
}

# Exporting methods
use Exporter;
our @EXPORT_OK = qw(first_method);
our @ISA = qw(Exporter);

BEGIN {
     print "Methods are exported from First\n";
}

sub first_method {
     print "Inside First::first_method\n";
}

1;
===================================================
# Second.pm
package Second;

use strict;
use warnings;

BEGIN {
     print "Start compiling Second\n";
}

BEGIN {
     print "Before using First in Second\n";
}

# Importing methods from Data.pm
use First qw(first_method);

BEGIN {
     print "After using First in Second\n";
}

sub second_method {
     print "Inside Second::second_method\n";

   # Calls imported method of First.pm
   first_method();
}

1;
===================================================
# driver.pl
use Second;

Second::second_method();

===================================================


If I compile driver.pl (by perl -wc) the output looks something like:

Start compiling Second
Before using First in Second
Start compiling First
Before using Second in First
Just used Second in Data
Methods are exported from First
After using First in Second
driver.pl syntax OK


If I compile Second.pm (using perl -wc) the output is:


Start compiling Second
Before using First in Second
Start compiling First
Before using Second in First
Start compiling Second
Before using First in Second
After using First in Second
Just used Second in Data
Methods are exported from First
After using First in Second
Subroutine second_method redefined at Second.pm line 21.
Second.pm syntax OK


First question that I have here is :
When I compile Second.pm, the compiler after seeing "use First qw(first_method);" starts compiling First.pm. But why it again compiles Second when it sees "use Second;" in First.pm as it is already compiling it.

The second questing is:
All that "driver" does is using "Second", so when I compile driver the perl compiler should do the same thing what it does when I compile Second.pm. But we both these compilation process are different?

Third question (I have asked this question before to Monks but did not get a satisfying answer):
First.pm uses Second and before it exports first_method. If we follow all compilation steps of Second, then we find that Second gets compiled for the second time, before it's actual compilation completes(weird). As far as I know Exporter's import method is executed at compile time. Strange thing here is that First did not exported any of its methods before using Second. So, in the second compilation of Second, by the time we are at "use First qw(first_method);", First's EXPORT_OK is empty, therefore the compilation should fail with error messages like
"first_method" is not exported by the First module
Can't continue after import errors at Second.pm line 21
BEGIN failed--compilation aborted at Second.pm line 21."


But the Second gets compiled without any such errors. Why?

TIA,
- Praveen.

Replies are listed 'Best First'.
Re: Strange problem with Perl Compiler
by almut (Canon) on Apr 25, 2008 at 15:27 UTC
    As far as I know Exporter's import method is executed at compile time. Strange thing here is that First did not exported any of its methods before using Second. So, in the second compilation of Second, by the time we are at "use First qw(first_method);", First's EXPORT_OK is empty, therefore the compilation should fail...

    Yes, import is executed at compile time, but after the respective module has been compiled in its entirety — not somewhere in the middle of use-ing one of its dependencies (after all, First.pm might have defined its own import method further down, which would of course have to be compiled before it can be called...). So, at the point when import is called, @EXPORT_OK is already set up; therefore it's no surprise you're not getting the '"first_method" is not exported by...' error message.

    If you add your own import method to First.pm, e.g. like this

    ... # Exporting methods use Exporter; our @EXPORT_OK = qw(first_method); our @ISA = qw(Exporter); sub import { print "First::import(): \@EXPORT_OK = @EXPORT_OK, args = @_\n"; goto &{Exporter::import}; # alternatively, if you dislike hardcoding stuff: # if (my $super_import = __PACKAGE__->can("SUPER::import") ) { # goto &{$super_import}; # } } ...

    you'll see that it is being called rather late.  Output of perl -wc Second.pm:

    Start compiling Second Before using First in Second Start compiling First Before using Second in First Start compiling Second Before using First in Second After using First in Second Just used Second in Data Methods are exported from First First::import(): @EXPORT_OK = first_method, args = First first_method After using First in Second Subroutine second_method redefined at Second.pm line 22. Second.pm syntax OK
Re: Strange problem with Perl Compiler
by mscharrer (Hermit) on Apr 25, 2008 at 13:05 UTC
    But the Second gets compiled without any such errors. Why?
    Mmm, probably because Perl is programmed to Do The Right ThingTM.
    I know that's not a real answer, but I still don't understand why you bother about it anyway.
    Do you have a specific problem with two modules like this? Do you just like to understand better how Perl is loading packages? Please give us some more information.

    As I already pointed out in my last reply to your last question functions seem to be looked up at run-time, which has nothing to do whether they get imported at compile or run-time. Look at the following example:

    shell# perl -we 'sub test { otherfunc(); }'
    This executes without a warning about otherfunc which doesn't exists, because test is never called and so otherfunc() must never be located by perl.

    Your way to only compile a module with perl -c module.pm looks strange to me - not the fact that it's not giving a warning.

    PS: Please use <readmore> tags for code with this length. You should also put every file in a own <code> </code> container so they can be downloaded separately.