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

I know Perl doesn't have an #include directive.

Instead, you're supposed to use use Foo; or require "Foo.pm"; or even do "Foo.pm";. Unfortunately, all of these seem to have side effects and semantics which conflict with one handy use of #include: organizing large flat modules into more manageable chunks.

I tried doing something like the following, but the value of __PACKAGE__ was not 'Mod' inside Mod-part1.pm, as I would have expected. Instead, it was of value 'main'. Thus, all the subs in Mod-part1.pm are added to the wrong namespace.

Mod.pm:

package Mod; use base 'Meta'; ... require "Mod-part1.pm"; require "Mod-part2.pm"; __END__ =pod ... =cut

Mod-part1.pm:

BEGIN { print __PACKAGE__, $/ } sub one { ... }

Mod-part2.pm:

BEGIN { print __PACKAGE__, $/ } sub two { ... }

Of course, this example is minimal; my example module has about six large subs in each of about six parts, all of which must (unfortunately) be in the same module namespace.

If I reassert the package name at the beginning of a part file, it loses all of the other common preparatory code like use base or other modules.

Any ideas on how I can avoid 4000 lines of many module subs in one source file?

--
[ e d @ h a l l e y . c c ]

Replies are listed 'Best First'.
Re: organizing large flat modules? use, require, do, ...
by chromatic (Archbishop) on Jan 10, 2004 at 18:54 UTC
    Any ideas on how I can avoid 4000 lines of many module subs in one source file?

    Rethink your design. Are there logical boundaries where you could subdivide your large module into smaller pieces?

Re: organizing large flat modules? use, require, do, ...
by dbwiz (Curate) on Jan 10, 2004 at 19:21 UTC

    You should follow chromatic's advice: rethink your design.

    But in the meantime, check 'package' and 'do' for some side effects of using non-modules to include code.

Re: organizing large flat modules? use, require, do, ...
by perrin (Chancellor) on Jan 10, 2004 at 22:08 UTC
    Here's a somewhat different idea: use AutoLoader. It comes with Perl. Normally, you write your code with all the subs after an __END__ tag, and then run autosplit to make them into separate files, but you could just code them as separate files in the first place. Then AutoLoader will handle loading them when you try to call a sub.
Re: organizing large flat modules? use, require, do, ...
by thpfft (Chaplain) on Jan 11, 2004 at 00:21 UTC

    While I agree that if you're going to break code into pieces it should be in response to some requirement of the code itself, I sympathise with the too-much-$@%! problem. Perhaps you could try:

    a different text editor
    This is a navigation problem, not a structure problem. Use an editor with better navigation features: syntax colouring, code folding, jump-to-method, position markers and good search tools will all help.

    more POD
    I find that well (and consistently) documented code is much easier to get around, especially if it has become unfamiliar. Consider spreading the docs throughout the module, rather than storing them at the end, and adopt a consistent structure to give easy visual cues when hunting for the right line.

    question your premises
    Why does it have to occupy a single namespace? That suggests a lot of globals or $package::variables, which will very likely have to be rooted out later for one reason or another. Refactor the requirement away.

    seek help
    Do you really need 4000 lines of code? Sifting carefully through CPAN could cut it down considerably and make it more readable too. Except I'm sure you did that already. And if all else fails:

    use mixin;
    mixins will let you separate code along whatever lines you like while preserving a single namespace. Schwern's adamantly lower-case module is very easy to use:

    Package My::Enormous::Package; use mixin 'My::Filingorsomething'; Package My::Filingorsomething use mixin::with 'My::Enormous::Package';

    Hope there's something useful in there. Please excuse if labouring obvious.

Re: organizing large flat modules? use, require, do, ...
by duff (Parson) on Jan 10, 2004 at 19:02 UTC
    Any ideas on how I can avoid 4000 lines of many module subs in one source file?

    Um ... put package Mod; at the top of each of Mod-part1.pm and Mod-part2.pm?

    The package statement doesn't propagate beyond file boundaries so you need to be explicit in your individual files

    Update: Sorry, I didn't see what you had written about use base (that's what I get for skimming rather than reading). Hmm. You can always declare your subs like this:

    sub Mod::foo { ... }

    And if variables are a problem too, then you would add

    use vars qw($Mod::var1 $Mod::var2 @Mod::var3 %Mod::etc);

    at an appropriate place. Note that this still won't make __PACKAGE__ have the value of Mod

    Why are you using __PACKAGE__ anyway? Do you need to? As chromatic said, perhaps you need to re-think your design.

    Also, you can always redeclare everything at the top of each module part:

    # Mod-part1.pm package Mod; use base qw(Meta); ... # Mod-part2.pm package Mod; use base qw(Meta); ...
      (I was only using __PACKAGE__ to see why things weren't being put in the right namespace.)

      The sub Mod::foo { } suggestion was a new thought, but like __PACKAGE__, the magic identifier SUPER was not correct. I would rather use SUPER than hardwire the base class, but it's pretty arbitrary.

      As for the many suggestions to rethink the design; yes, it's a good idea to rethink it. However, I've rethought, and in my particular case, it rightfully should be one class with a few semi-distinct duties that are not easy to aggregate or embed or delegate. I'm working near the base of a large class hierarchy, and the base classes really must cover their core duties.

      --
      [ e d @ h a l l e y . c c ]

        Then I would think that restating the package and base class (and whatever else you need) at the start of each module part is your best bet.

Re: organizing large flat modules? use, require, do, ...
by exussum0 (Vicar) on Jan 10, 2004 at 18:56 UTC
    You could export what you need from your sub-packages into your current package. Functions..data.. what have you.

    Play that funky music white boy..
Re: organizing large flat modules? use, require, do, ...
by Aristotle (Chancellor) on Jan 11, 2004 at 01:51 UTC
    do, require, use, it doesn't matter — they all lead to an eval. If you don't want them, set up your own middle man to deal with the filesystem.
    $ cat tt.pl sub foo { print "bar\n" } $ cat ttmain.pl package x; eval `cat tt.pl`; x::foo(); $ perl ttmain.pl bar
    Backticks and cat to prove the concept. Picking something robust to suit your needs is up to you.

    Makeshifts last the longest.

Re: organizing large flat modules? use, require, do, ...
by ysth (Canon) on Jan 11, 2004 at 06:38 UTC
    If I reassert the package name at the beginning of a part file, it loses all of the other common preparatory code like use base or other modules.
    use base, setting @ISA, @EXPORT*, @VERSION, etc., should only need doing once. It should be fine to just put package at the top of your sub-modules. If you are concerned that they might be used without the top Mod.pm, put a use Mod (); at the top for each sub-module.
    Any ideas on how I can avoid 4000 lines of many module subs in one source file?
    Why do you need to arbitrarily divide your module up? (If you had > 65535 lines and were using perls older than 5.8.1, I could understand.)
Re: organizing large flat modules? use, require, do, ...
by jaldhar (Vicar) on Jan 12, 2004 at 19:38 UTC

    I know Perl doesn't have an #include directive.

    Sure it does. the -P flag to perl runs the code through cpp first. Here's a quick example:

    #!/usr/bin/perl -Pw use strict; #define CHOICE 1 print "Hey look! I'm", #ifndef CHOICE ' not', #endif " using the C preprocessor.\n"; # Here is an example of #include. my $passwd = <<'-PASSWD-'; #include "/etc/passwd" -PASSWD- print "Here is /etc/passwd: $passwd\n";

    note -P can have problems distinguishing between preprocessor directives and perl comments. Also I don't know how well it works on non-Unix platforms where cpp might be missing. All in all it's a poor solution to your problem but it's there if you do need to us it.

    --
    જલધર