InnovWelt
InnovWelt

Reputation: 660

Perl `use` - import is not called twice?

Doubt in perl basics use

it is somewhat similar to my other question Perl: Two packages in same file...

consider a perl script:

Script.pl

use INCLUDES;

INCLUDES.pm

package INCLUDES;
use Exporter;

############# MY DOUBT STARTS HERE ###############
use Module1;
use Module2;
##################################################

our @ISA = qw(Exporter);
our @EXPORT = qw();

sub import {

  print 'INCLUDES imported to ' . caller . "\n";

}

Module1.pm

package Module1;

use strict;
use Exporter;
use INCLUDES;    #####=> INCLUDES.pm 'use'd

our @ISA = qw(Exporter);
our @EXPORT = qw();

1;

Module2.pm

package Module2;

use strict;
use Exporter;
use INCLUDES;  #####=> INCLUDES.pm 'use'd

our @ISA = qw(Exporter);
our @EXPORT = ();

1;

OUTPUT

D:\Do_analysis>Script.pl
INCLUDES imported to main

According to perl docs, use INCLUDES; in Module1 & Module2 => BEGIN {require 'INCLUDES.pm'; 'INCLUDES'->import();} . So, the import() should be called in Module1.pm , Module2.pm also.

I would expect the output as something like below,

EXPECTED OUTPUT ??

D:\Do_analysis>Script.pl
INCLUDES imported to main
INCLUDES imported to Module1
INCLUDES imported to Module2

But why is the execution not as expected?

UPDATED

This is what I am trying to achieve, by having the INCLUDES.pm file.

Module library

Note that: PACKAGE2 might want to access PACKAGE3, PACKAGE4 etc. Instead of useing all the modules inside PACKAGE2 seperately, I would like to create a Library INCLUDES and use it in all other modules.

Is this approach valid? or recommendable?

I appreciate any idea about how to achieve this. Thanks!

Upvotes: 3

Views: 553

Answers (2)

hobbs
hobbs

Reputation: 239841

You have circular dependencies between your modules. main uses INCLUDES, INCLUDES uses Module1, and Module1 uses INCLUDES (Module2 is basically irrelevant here, except to act the same as Module1). If perl did the naïve thing, this would cause an infinite loop (or at least a stack overflow), as every time perl tried to compile INCLUDES it would lead to a compilation of Module1, and every time perl tried to compile Module1 it would lead to a compilation of INCLUDES.

Since we don't want that to happen, perl has to do something different. What it does instead is to ignore any request to compile a module that's already compiled or that it's already in the process of compiling. So the flow of events is:

  1. Perl begins compiling script.pl and enters the package main.
  2. Perl sees use INCLUDES;, loads INCLUDES.pm, and begins compiling it.
  3. At the line package INCLUDES;, perl enters the package INCLUDES.
  4. Perl sees use Module1;, loads Module1.pm, and begins compiling it.
  5. At the line package Module1, perl enters the package Module1.
  6. Perl sees the use INCLUDES;, realizes that it's already in the process of compiling INCLUDES.pm, and doesn't attempt to compile it again.
  7. As a result of use INCLUDES; perl tries to call INCLUDES->import, but the import method hasn't been defined yet (we suspended compilation of INCLUDES at step 4 to start compiling Module1).
  8. Compilation of Module1 completes and we go back to INCLUDES.
  9. Perl calls Module1->import from INCLUDES.
  10. Compilation of INCLUDES completes, including the use Module2 and the definition of sub import. Perl goes back to main.
  11. INCLUDES->import is called from main and your message is printed.
  12. Compilation of script.pl completes.
  13. script.pl has nothing to do at runtime, and perl exits.

Upvotes: 3

ikegami
ikegami

Reputation: 385647

If you were to move

use Module1;
use Module2;

below sub import { ... }, you'd get the expected behaviour.


The problem is that you execute Module1.pm before the compiler even reaches sub import in INCLUDES.pm.

When Module1.pm does use INCLUDES;, Perl says "oh, it's already loaded" (in response to require) and "oh, it doesn't have an import" (in response to import), since the part of INCLUDES.pm that would have created import hasn't been compiled yet. Same for Module2.pm.

Generally speaking, if you have a modules that include each other (directly or otherwise), you're doing something wrong (in terms of design), and you'll end up having to deal with such issues. You might find Mini-Tutorial: Mutual Use of Exporting Modules useful in dealing with these issues.

Upvotes: 9

Related Questions