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

First off I need to admit when it comes to modules I am dumb as a brick. That having been said, I have a friend who is developing an application for a project we are working on. I am co-developing. He is doing something that I have never seen before and am still a little bit weary of it. Admittedly, I am weary not because I can think of an adversity to using this method but that I am simply not used to this.

What he is doing is modularizing. This is good except that every module he's creating he's calling it 'package main;' essentially (I believe) placing every module as a piece of the calling main body. Ok, in theory this is what sounds like is happening, however, I am running into a snag.

Whenever I try to edit my piece of the pie and then execute it, my subs get compiled and *run*!!! thus failing because, well, nothing is being passed to them yet, or in other words, a bunch of undefs are being seen hence unitialized variables in the symbol table when I try to do something in the sub with a variable. Technically, though, I'd think that nothing should be being done with these subs yet anyway. At least not until the main body calls my code. *shrug*. Im not sure. I've read the docs but I must either be missing something or the package main; being placed at the top of every module is throwing me off.

Any foresight would be greatly appreciated!

TIA

_ _ _ _ _ _ _ _ _ _
- Jim
Insert clever comment here...

2002-04-21 Edit by Corion - moved from Meditation to SoPW

Replies are listed 'Best First'.
Re: A lil module creation advice
by rinceWind (Monsignor) on Apr 20, 2002 at 10:17 UTC
    snafu,

    Are the modules in question .pm files being used (pulled in at compile time) or .pl files being required (at run time)?

    I suspect the former. If a used file is pulled in, any mainline code (not part of a sub) actually gets run at compile time - as if it were in a BEGIN block.

    This is handy for initialisation code, but if your colleague is stuffing application code in here, it will indeed happen at compile time.

    On the subject of package main;, this just means that any subs will be placed in the main:: namespace, thus defensively negating any package declaration prior to calling the module. IMO this should not be done, as the module should not be dictating the namespace to its caller, (unless we are talking OO, which is a different ball game).

    Also note that leaving the use or require restores the namespace to that of the calling code.

    For more on this, see perldoc perlfunc sections on use and require. I also recommend buying a copy of the Camel book for your colleague.

    I may be able to answer more specifically if you post some code.

    hth

    --rW

      <indent>Are the modules in question .pm files being used (pulled in at compile time) or .pl files being required (at run time)?</indent>

      Yes. These files are called script_name.pm with their first line containing package main; and every module that is being written is being called from the main script as use script_name. Now, I realize that this i s just basicly placing the namespace of each script into main:: which is fine but I am still not clear why my subs are being run at compile time.

      Here is a portion of my code:

      38 my %sn; # temporary 39 $sn{chanserv} = "ChanServ"; # temporary 40 41 my $_name = $sn{chanserv}; 42 my($_source,$_data) = (shift,shift); 43 44 $_data = &_cs_parse_raw_cmd($_data) if $_data; 45 &_sendit($_name,$_source,$_data); 46 47 # ************************************************************ 48 # sub routines 49 # ************************************************************ 50 51 # *** 52 # _send_it(): simple wrapper for chanserv to send data 53 # through the main socket. 54 # *** 55 56 sub _sendit 57 { 58 my $_channel = shift; 59 my $_message = shift; 60 61 # send_data(':%s ! %s :%s', $_name, $_channel, "I saw your + message: $_message"); 62 printf(":%s ! %s :%s\n", $_name, $_channel, "I saw your m +essage: $_message"); 63 } 64 65 66 # *** 67 # _cs_parse_raw_cmd() : parses out raw data from main destined 68 # for chanserv. This will parse the raw packet. 69 # *** 70 71 sub _cs_parse_raw_cmd 72 { 73 my ($cmd) = @_ ; 74 75 # Chanserv :test 76 # ChanServ@Services.Netfrag.Com :test 77 78 my ($_to_whom, 79 $_message) = split(/:/,$cmd); 80 81 # First, make sure that we are the right one getting call +ed 82 unless ( /\#/ ) { 83 if ( lc($_to_whom) !~ m/$_name/i ) { 84 &sendit($_source,"Please let an admin know that s +omething is broke."); 85 } 86 } 87 88 return($_message); 89 } 90 91 1;

      Now. I have just spoken to the main coder about my issue and he made it clear that what I was doing was setting a scalar by calling a function which of course I was but that this was causing the problem. He also said that I needed to simply make a bunch of functions and not worry about creating any global scalars or arrays.

      Everything makes sense to me now but Im still curious what the other monks think.

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...

        Now. I have just spoken to the main coder about my issue and he made it clear that what I was doing was setting a scalar by calling a function which of course I was but that this was causing the problem. He also said that I needed to simply make a bunch of functions and not worry about creating any global scalars or arrays.
        Nice to see that you got to the bottom of it. Global variables are generally agreed to be bad news, and show up quite clearly with
        use strict;
        In fact, if you try to run code with global variables in an Apache+ModPerl configuration, it will break in strange, wonderful and inconsistent ways.

        As greywolf says, use strict; is your friend.

        See also this thread for a discussion on use of global variables.

Re: A lil module creation advice
by Ryszard (Priest) on Apr 20, 2002 at 07:25 UTC
    Sounds to me like you need a pretty specific spec to code to.

    One of the fundemental concepts I use when coding (whether OO-style or using my functional-fu) is high cohesion, low coupling.

    What this translates to is each "interdependant" block of your should almost be able to be executed standalone, ie it takes input, does some processing and spits something out. In reality this translates to having all the infrastructure to operate standalone (eg db handles, file handles etc)

    So, given this coding style, it should be relatively easy to create a test.pl to test all your methods, based on the specification.

    Even before you put fingers to k/b there is a process known as "bench testing" which means, taking the technical design (while still on paper) and running data thru' it (still on paper (or virtual paper)). Once you are satisfied with the paper design, you start to cut the code.

    I guess the main point is planning. You must take the time to plan good code and good systems.

Re: A lil module creation advice
by impossiblerobot (Deacon) on Apr 20, 2002 at 13:55 UTC
    If the other answers haven't solved your problem(s), I'll take my shot (which is the best I can do without more detail).

    My guess is that you are trying to use my (lexical) variables globally. Unfortunately, lexical variables are not technically in any package, and their scope does not reach outside of the file they appear in (even if that file is required into another file). Therefore they will show up as undefined.

    If your portion of the code is in subroutines, then I would suggest you follow Ryszard's suggestions, and pass all the variables you need to the sub, then use the return from the sub. You can then use my variables internally to the sub with no problem.

    Otherwise, you'll probably have to use 'real' globals, defined (for example) with use vars(). But, in my opinion, that would be a design mistake. My guess is that your code does not use strict. Could you give us a little more detail on the current design (maybe even some code) to make it easier to give helpful recommendations?

    Impossible Robot
Re: A lil module creation advice
by greywolf (Priest) on Apr 20, 2002 at 15:58 UTC
    Is your module failing by being run or failing at compile time?

    Every module that is 'used' must compile properly or the entire program will fail before it is run.

    'use strict' will tell you exactly where the program is failing. Sending some debugging to the screen will tell you how much of the program is being run before failing.

    mr greywolf
      Well. This is a good question that I overlooked making clear when I started this thread.

      The program I am writing compiles just fine by itself. It even runs at runtime but the fact that my subs get executed at runtime when they should only be run when called is what's causing the whole script to fail.

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...

      Hmm. I thought I submitted a reply to this one already but I must have overlooked the submit button a few days. Anyhoo, just so everyone knows...

      I was using strict; as I always do, religiously. I learned my lesson on that one way back at the beginning of my Perl coding days. This suggestion from greywolf, btw, is always an excellent suggestion, nay, rule!

      The script in question was compiling fine by itself.

      Thanks for the input everyone. I just needed to make those two points clear so that at least people knew I wasn't a total tard :)

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...