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

I'm doing some more experimenting with moving from library (.pl) files and onto module (.pm) files and their creation and I'm wondering about style/usage.

The attached code has a reference number beside each line in the main code. To try things out, uncomment each of the #1 lines, or the #2 lines, etc. I know all of the lines of code work Ok but is there an 'accepted standard'?

My *preference* would be to use the fully-specified function name in a module (Option #2) but I can see how that might be cumbersome - hardly any of the (non-OOP) CPAN modules use the fully-specified convention. It seems like most of them use Option #3... but I like Option #2 in terms of documentation.

How do other people prefer to write.. and read... their/others' code?

Many thanks for your thoughts.


John

# ---- # Main Code require 'mylib.pl'; # [ 1 ] #use MyModule; # [ 2 ] #use MyModule qw(:All); # [ 3 ] printf("timestamp: %s\n", mylib::timestamp(time)); # [ 1 ] #printf("timestamp: %s\n", MyModule::timestamp(time)); # [ 2 ] #printf("timestamp: %s\n", timestamp(time)); # [ 3 ] # ---- # mylib.pl package mylib; #use Time::Local; sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } sub timestamp { my ($timer) = @_; my ($ret); $ret = localtime($timer); } # End of timestamp 1; # ---- # MyModule.pm package MyModule; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(func1 func2 timestamp); %EXPORT_TAGS = ( DEFAULT => [qw(&func1)], Both => [qw(&func1 &func2)], All => [qw(&func1 &func2 &timestamp)]); sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } sub timestamp { my ($timer) = @_; my ($ret); $ret = localtime($timer); } # End of timestamp 1;

READMORE tags added by Arunbear

Replies are listed 'Best First'.
Re: Module Style and Usage
by xdg (Monsignor) on Sep 07, 2005 at 08:55 UTC

    Generally, the commonly given advice is not to export anything by default. I.e. everything goes in @EXPORT_OK, nothing goes in @EXPORT, and it's helpful to include some sort of :all or other subsets in %EXPORT_TAGS. I think that's your option (2). The benefit is that it gives the most flexibility to your end-user. They can use fully-qualified names if they prefer, or they can import the function if they'd rather use a shorter name. I would find it annoying if you didn't put your functions into @EXPORT_OK and give me the option (and I'd probably just wind up doing my own aliasing if I was using a function frequently anyway).

    What I believe is a common exception to that guideline is the case where a module only provides a few functions (or even just one!) and the whole point of the module is to make those functions available for frequent use. (E.g. Test::More and most of the Test:: modules.) In such cases, I personally think that putting these into @EXPORT is the right thing to do.

    So my guidance is to think about what would be the most likely usage of the module and let that be your guide. If there are functions that 9 out of 10 users would import anyway, stick those into @EXPORT. Otherwise, put them all into </code>@EXPORT_OK</code> and include at least an :all tag.

    (Note: I'm only speaking to function names above. I'd never advise automatically exporting package global variables and would discourage using even fully qualified package globals as an "interface" mechanism to your module.)

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: Module Style and Usage
by hv (Prior) on Sep 07, 2005 at 10:30 UTC

    I will usually access external functions in one of two styles:

    use Your::Module (); printf "timestamp: %s\n", Your::Module::timestamp(time); use Your::Module qw/ timestamp /; printf "timestamp: %s\n", timestamp(time);

    I use these styles because I don't like action at a distance. When looking at a function call in my code, I want it to be clear either from the line of code itself or from a declaration in the same source file where I'd find the function being called.

    Further, when allowing an unspecified import, there is always the danger that the name of an exported function clashes with a local name. I don't want to have to check for that when I use a module, and I certainly don't want to have to check for it throughout my code when I upgrade a module.

    Most of the modules I write myself are OO, so this question doesn't arise. For the few that include only functions, I don't use Exporter: I expect the caller to fully qualify calls, or set up their own alias - which is as simple as:

    *timestamp = \&Your::Module::timestamp;

    Hugo

Re: Module Style and Usage
by parv (Parson) on Sep 07, 2005 at 08:53 UTC

    If more than one modules are going to be used in a program i am writing, i would incline toward those which support OO interface to avoid name space pollution/conflict. Lacking OO interface from a module, i would import only those functions that i would need; i don't bother w/ using the package name. In case of (function name) conflict, i create my own wrapper function.

    Due to the above reason, i personally write only the modules supporting OO interface.

Re: Module Style and Usage
by Smylers (Pilgrim) on Sep 07, 2005 at 13:23 UTC

    Hi. You're right that option 3 is poor from a documentation point of view — the person reading the main script and encountering the timestamp function can't see where it's defined.

    But you don't have to go as far as option 2 and fully qualify the name every time. Just change the use statement to:

    use MyModule qw<timestamp>;

    and then it's clear exactly where that function is coming from.

    Smylers

      Side note: just because you can't see where it's coming from isn't always a bad thing. It makes it easier to adjust the behaviour.

      Option 1: Say you have a MyModule with timestamp in it. Now a new corporate standard says all company-owned modules should be in the Example namespace. All you need to do is change the modules themselves (including moving them to the Example subdirectory) and the "use" statements. The rest of the code will work as-is. (This is also a reason to use __PACKAGE__ when referring to one's own package rather than hardcoding the name again and again - the other reason is to aid in cut&paste from module to module.)

      Option 2: Say you're using CPANModule's timestamp. And you find a bug. So you go write MyCPANModule, reimplementing a timestamp that works, and all you need to do is change the use statement. You don't need to go changing all the code.

      Option 3: Say you're using CPANModule's foo function. Which calls CPANModule2's timestamp - which is broken or just not working quite the way you want it to. If CPANModule is calling "timestamp" rather than "CPANModule2::timestamp", then you can just "use CPANModule" and then play with the symbol table and "import" your own timestamp function into CPANModule's namespace with whatever modifications you want, which will overwrite the import from CPANModule2 since the import from CPANModule2 will happen during compilation and yours will happen during runtime. (Technically, it could be during compilation as well, but after the compilation of CPANModule and thus also after compilation of CPANModule2.)

      Part of the idea of not naming your namespaces is to allow perl to actually Do What You Mean. Even if it's not your code ;-)

Re: Module Style and Usage
by ozboomer (Friar) on Sep 07, 2005 at 22:22 UTC
    Heh... I *love* how one's brain works...

    > Option 1: Say you have a MyModule with timestamp in it.
    > Now a new corporate standard says all company-owned
    > modules should be in the Example namespace. All you need
    > to do is change the modules themselves (including moving
    > them to the Example subdirectory) and the "use"
    > statements. The rest of the code will work as-is.

    I woke-up at about 3:00am this morning with this particular revelation.

    I've been working on a program to parse all my Perl code (more than 1000 programs at last count) to find all the instances of calls to my 'mylib.pl' functions and I was thinking the 'crossing' of all the function names with every line of code was going to be kindof horrendous. Then comes *this* little spark... and all I (might) have to do is change the 'require mylib.pl' to 'use MyModule' (providing the exports, etc are all Ok). I might *still* have to do it... but at least I have a possible shortcut :)

    As usual, there's always a few ways to do things... some better than others in terms of documentation, re-use, namespace clashes, etc.

    Many thanks, once again, Monks :)


    John

Re: Module Style and Usage
by ozboomer (Friar) on Sep 08, 2005 at 03:07 UTC
    Well, I've had a go... and I'm managing to get some of this module code working and I'm understanding it as well :) Thus, I've decided to code-up some example usage to illustrate what I've found out.

    Here's what I have so far:

    # Q.pl - mainline code use Q2 qw($myfile func1 $SM_HDR_REC); # ---- printf("\$Q2::myfile: >$Q2::myfile<\n"); printf("\$Q2::myport: >$Q2::myport<\n"); # Not exported but still # usable by fully-specifying printf("\$myfile: >$myfile<\n"); # Ok 'coz it's exported printf("\$myport: >$myport<\n"); # Unknown 'coz not exported printf("SM_HDR_REC: >$SM_HDR_REC<\n"); # Declared 'our' in Q2.pm # ---- $buf = "test_string"; printf("\nFn call into temp var:\n"); printf("String before: %s\n", $buf); $newbuf = func1($buf); # Works! printf("String after: %s\n\n", $newbuf); $buf = "test_string"; printf("Fn call only:\n"); printf("String before: %s\n", $buf); printf("String after: %s\n\n", func1($buf)); # Doesn't work!? # Q2.pm - module code package Q2; use strict; use Exporter; # ---- use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw($myfile &func1 &func2 $SM_HDR_REC); %EXPORT_TAGS = (DEFAULT => [qw(&func1)], all => [qw(&func1 func2 $myfile)]); # ---- use vars qw($myfile $myport); $myfile = 'FRED.DAT'; # Used locally and exported (above) $myport = "OPA0:"; # Used locally but not exported # ---- our $SM_HDR_REC = "HDR"; # ---- sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } END { }; 1;
    The only question I have is the call to func1 -- the two calls in the mainline program above give different results. Is there something with how the function is being called or exported... or am I missing something obvious?


    John

      Difference is due to the different behaviour of reverse() dependent on (list|scalar) context; see the perldoc on it. In the "non working" case, printf() causes the list context for func1() causes the list context for reverse(). Try forcing the scalar context...

      printf("String after: %s\n\n", scalar func1($buf));