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

I'm working on a very large project that has a lot of modules. Unfortunately many of the modules use use too capriciously - they use modules that they really don't need to use. The result is that just by using one module you can pull in half of the code base.

Here's an example of what's going on. A module X might look like this:

package X; use Order; sub doSomething { my ($self, $order) = @_; # $order is an Order object ... $order->some_method(...); }
However in this case X never creates objects of class Order - it merely has a subroutine which expects an Order object as a parameter. Therefore use Order; here is not necessary. The caller of X::doSomething might have to use Order; to create the argument to doSomething.

In thinking about the problem I've come up with this general rule about using use: only use modules whose name space your module directly references. Just because your module interacts with objects of a certain class doesn't mean it needs to pull in that class.

Of course for every rule there are always exceptions. And there are a lot of different ways in which use is used in perl. What do you think?

Replies are listed 'Best First'.
Re: general rule for using use
by moritz (Cardinal) on Apr 08, 2009 at 20:04 UTC
    The result is that just by using one module you can pull in half of the code base.

    So, is that a problem? Or asked differently, what kind of problem are you actually trying to solve?

    Does your application use too much memory? or is the startup time too large?

    If you don't have a problem, don't worry. Remember Donald Knuth's wisdom: "premature optimization is the root of all evil".

    The reason that this "don't use stuff that you don't need the namespace of" thing sounds weird to me is that I don't think it works. In your example above, $order comes somewhere. Wherever it comes from, that module actually loaded the module Order - probably at compile time, and unconditionally. So it gets compile once anyway - and if you use use it multiple times from different places, it's still only compiled once.

      Thanks for reminding my of Knuth's sage advice.

      I think what I'm getting at is that using Order in X is misguided. When we say that doSomething() operates on an Order object, we are really saying that it operates on an object that behaves like an Order. It could be an instance of Order or an instance of a sub-class or just a mocked-up object that implements enough of the methods of an Order to make it look like an Order to doSomething().

      There may be no harm in including it, but on the other hand I can't think of a compelling reason to do so. If a real instance of Order will get passed to doSomething, then the caller can be responsible for ensuring that the Order name space is loaded.

      Perhaps I forgot to mention that this particular application consists of 800+ modules, and all of that unnecessary module loading is a big drag on unit testing.

        Good question this ++ for that. I often think like this and some times I write my own simple module(in terms of number of lines of code) for solving problems rather than using a third party one, since there are lot of dependencies and it is really painful, it pulls thousands of lines of code un-necessarily, but it might be designed to work in all platforms, much reliable, etc, I seriously don't want to complain any third party module, this is my opinion

        What you are trying to do? UNIT Testing or adding any new feature into the code?.
        if UNIT Testing, better don't disturb the flow of the code, just test as it is.
        if you are planning to add any new feature or if you want to re-engineer the entire code(since you don't like to load 800+ modules and you think it can be done in a simpler way), if you know the clear requirements, better write you own code which uses simple set of modules which meets your requirement(provided if you have time, if you don't have time, just understand the existing code base and find out why they have done like that, nothing would have been done for no reason, better note down drawbacks and do it later when you have time).


        Vivek
        -- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.
        Perhaps I forgot to mention that this particular application consists of 800+ modules, and all of that unnecessary module loading is a big drag on unit testing.

        If it's only testing that's slow (and not the "real" uses of your program, whatever that may be) maybe the right thing to do is to change the testing? For example load the app only once in one process, and then read the test files in that process and run them in order?

Re: general rule for using use
by ikegami (Patriarch) on Apr 08, 2009 at 21:28 UTC

    The result is that just by using one module you can pull in half of the code base

    Not at all. The modules have already been loaded to create the object. Removing it will not speed up your program and it will not save memory. That means use Order; is purely documentation, and that's not bad.

Re: general rule for using use
by JavaFan (Canon) on Apr 09, 2009 at 09:26 UTC
    Just because your module interacts with objects of a certain class doesn't mean it needs to pull in that class.
    If your module interacts with objects of a certain class, and the code of that class hasn't been pulled in, your program will die.

    Now, either your module "pulls" in the code, or some other module has already done so. In the former case, the "use" prevents your program from crashing, in the latter case, all that's lost is some triviality at compile time ("Oh, golly, they want me to "pull in" this module - lemme see, I've already done that! Nothing to do").

    Don't get me wrong, I don't advocate using modules you aren't going to use (in fact, I often use 'require Module' in a sub if I just need that module in the sub, and the sub isn't commonly called), but your example, and suggestion how to deal with it don't really convince me.

Re: general rule for using use
by dsheroh (Monsignor) on Apr 09, 2009 at 21:54 UTC
    Multiple comments thus far have said that use Order is essentially a no-op, because the calling code will have already included Order. This is guaranteed if and only if every sub in X will be used - which is hardly a foregone conclusion.

    Imagine, if you will, that package X has defined both sub do_something_to_order and sub do_something_to_customer. If X is then referenced by a customer management application, the app will not be importing Order (or calling do_something_with_order) because it doesn't do anything related to orders. In this case, leaving use Order out of package X will prevent Order from being (needlessly) included.

    I don't think this situation is much of a stretch if you're talking about modules which are used in more than one place. When was the last time you used a (non-trivial) CPAN module and your code (directly or indirectly) called every single sub present in that module?