Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Mini-Tutorial: Mutual Use of Exporting Modules

by ikegami (Pope)
on Jul 09, 2009 at 17:55 UTC ( #778639=perlmeditation: print w/ replies, xml ) Need Help??

[ The need to use this technique is a very strong indicator of a design flaw in your system, but I recognize that the resources are not always available to fix design flaws. ]

If ModA uses ModB, ModB uses ModA, and ModA or ModB imports symbols from the other, one needs to pay attention to code execution order. The best way I've found to avoid problems is to setup Exporter before loading any other module.

# ModA.pm package ModA; use strict; use warnings; BEGIN { our @ISA = qw( Exporter ); our @EXPORT_OK = qw( ... ); require Exporter; } use This; use ModB; use That; ... 1;
# ModB.pm package ModB; use strict; use warnings; BEGIN { our @ISA = qw( Exporter ); our @EXPORT_OK = qw( ... ); require Exporter; } use This; use ModA; use That; ... 1;

Update: Added preamble. Details can be found in Jenda's and tilly's replies.

Comment on Mini-Tutorial: Mutual Use of Exporting Modules
Select or Download Code
Re: Mini-Tutorial: Mutual Use of Exporting Modules
by Jenda (Abbot) on Jul 09, 2009 at 23:04 UTC

    If ModA uses ModB and ModB uses ModA, you should sit down and change them both to use ModC instead.

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

      What if ModA is Car and ModB is CarEngine? There's nothing inherently wrong with the concept. Sometimes refactoring is in order. Sometimes it's not. (And sometimes, refactoring is not an option for business reasons.)
        CarEngines can be put in things other than cars.

        I have yet to see a case of circular requires that would not be much clearer if refactored. I have, however, great sympathy for the situation where refactoring is not an option for business reasons.

        If ModA is Car and ModB is CarEngine then I understand that the Car wants to import CarEngine because Car HasA CarEngine, I don't see why would CarEngine import Car. Even if it later keeps a IsIn reference.

        The concept makes about as much sense as multiple inheritance. It looked like a good idea at first, but it causes too many subtle and hard to debug problems. Which is why things like mixins were invented. Though of course it means a bit of refactoring, instead of merging two classes and hoping for the best.

        Jenda
        Enoch was right!
        Enjoy the last years of Rome.

Re: Mini-Tutorial: Mutual Use of Exporting Modules
by roubi (Hermit) on Jul 10, 2009 at 00:28 UTC
    That's basically what the doc for Exporter already says no? Or is "before loading any other module" the critical piece of information in your post?
      Yes
Re: Mini-Tutorial: Mutual Use of Exporting Modules
by tilly (Archbishop) on Jul 10, 2009 at 04:30 UTC
    You shouldn't need to solve this problem.

    If you do, the best solution should be to make one module use the other, and the other one require the first inside of the function(s) that need it. This gives a predictable loading order. For an example look at the source to Carp and Exporter.

    If each really does need stuff from the other, and you're unwilling to use/require, then I would still suggest the cleaner pattern:

    use Exporter qw(import); BEGIN {@EXPORT_OK = qw( ... );}
    That makes the magic BEGIN block much shorter. And it avoids inheriting all of Exporter.

    Also you need to warn people that it is very important that neither module in its initialization can do anything that relies on the other module being fully loaded yet. Because if the other module is used first, then its compilation will be put on hold to load this one, and therefore while this module gets loaded, that one will not be loaded. I've seen people get badly bitten by this, and get in a situation where one module breaks if the other is loaded first, or worse yet where neither works if the other is loaded first. (And that is one reason that I recommend the use/require relationship instead of use/use.)

    If this scares you, then I'd suggest thinking through your problem clearly enough to not need to do circular dependencies. Many other languages don't even allow them, and I don't think that is a particularly bad restriction.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://778639]
Approved by linuxer
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (13)
As of 2014-12-26 06:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (167 votes), past polls