Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

subroutine good practise

by Anonymous Monk
on Oct 29, 2012 at 18:02 UTC ( [id://1001398]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks I'm still writing perl 4 style code. I hope to change that soon. In the meantime, we have some large in-house scripts calling many subroutines, contained in several .inc files. Opinion here is divided as to whether each .inc file should contain appropriate use and require statements for the subroutines it contains, or if the subroutines themselves should contain those statements as required. I would be grateful to know which is the safest and most efficient method.

Replies are listed 'Best First'.
Re: subroutine good practise
by eyepopslikeamosquito (Archbishop) on Oct 29, 2012 at 19:10 UTC

    Because use statements are performed at compile time (while require statements are performed at run time), I find it clearer to put all use statements together at the top of the file.

    This was discussed in: Code style advice: where to put "use" statements?

Re: subroutine good practise
by chromatic (Archbishop) on Oct 29, 2012 at 18:49 UTC

    I find it easier to understand a file when all of its use statements appear together near the start of the file.


    Improve your skills with Modern Perl: the free book.

      What do you suggest in cases where a module's conditionally needed? For example, a program only needs either Text::Table or HTML::Table, depending upon how that program's called. Should both modules be loaded or conditionally loaded?

      For example:

      # Conditionally use Modules based on outFormat for ( $config{outFormat} ) { when (TEXT) { eval 'use Text::Table'; die $@ if $@; } when (HTML) { eval 'use HTML::Table'; die $@ if $@; } }

      If conditionally loaded if acceptable, would require be better than use in the above case?

        If you must encode this within the module itself, I prefer using something like the if pragma.

        My preference is to pass in the dependency when using the module from the calling code, as it sounds like the calling code is most responsible for deciding which dependency to use.

        Have you tried measuring how much difference it will make in the run-time and size of the program to just use both modules? I'm very doubtful that this conditional use will buy you a significant amount of anything, but you're the one who can measure what you're doing.

        It also seems to me that you'd be better served by moving those "use"s to the code which needs them, which should probably be in different modules.

        I'd say that depends on whether you would expect that script to use both modules in the end, e.g. if this is in a loop and every time you have a 50% chance of one or the other being needed than you might as well load (use) both modules at compile time with the added advantage of having all your requirements at the top of your script instead of somewhere in a sub.
        Measure. Don't tune for speed until you've measured, and even then don't unless one part of the code overwhelms the rest. ~Rob Pike

        What has measurement shown the difference is between conditionally loading the modules and just loading them all to begin with? If it's not worth measuring, it's not worth optimizing. You then have to weigh that difference in performance against making your code less clear, less maintainable, more complex and less testable.

        I think you'll find that the most straightforward strategy of loading all your modules at the beginning of the file makes the most sense.

        A couple additional notes:

        If your module loads a large number of only loosely-related modules, a code reorganization may be a better strategy. But even that may be more trouble than it's worth unless there are additional reasons to do it.

        If your module is large with lots of subroutines, you might consider adding a comment to each subroutine about what module(s) it uses. That makes it easy to detect if there are any loaded modules that are no longer used in your subroutines.

Re: subroutine good practise
by sundialsvc4 (Abbot) on Oct 29, 2012 at 20:18 UTC

    In my opinion, when a program is constructed in such a very “dynamic” way (for what purpose?   “efficiency?”), it becomes utterly impossible to test it.   It becomes, in effect, many different possible programs, depending on (as you say) “how it is called.”   This practice is completely unacceptable to me, due to the inherent business risk.

    In my experience, most such programs can be, perhaps with some effort, “de-fused” into one or more modules of common-code which can then be used by the specific in-house script that invokes them.   These scripts ought not attempt to make any decisions as to what code they do or do not invoke, and they should universally use use to do so.   (This is not, of course, an impregnable requirement, but IMHO it is very nearly so.   Obvious exceptions such as RPC::Any::Server are also very-limited in what they do and how they do it, and the required modules are also clearly “top-level handlers,” effectively selecting among possible scripts to call; not the case here.)

    Any piece of software that is in service needs to be buttressed by independent, automated tests that can demonstrate that, in every case which that piece of software supports, the software works correctly.   If what the piece of software is composed of is subject to variation, that becomes pragmatically impossible to do.   What a group of scripts have in common, reasonably should be in-common, so that the common pieces can be tested and the tests will cover all of that code’s users.   If thereby the program contains code that it does not make use of in the course of any particular invocation ... who cares.   Such is of no consequence.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1001398]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-25 17:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found