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

I have a file that contains a bunch of subroutines. These subroutines are used in other files which declare namespaces with package.

This file also contains subroutines that are method calls in these packages. For example:

# the new method is in the file. my $p = $namespace->new; # do_this is also a method in this other file my $p->do_this()
One solution is to make this file a base class. But that only works if I am only making method calls. I am not. I am also calling functions like this:
# function_call is a subroutine in that same file my $text = function_call();
So if I don't make this file a base class, I thought of turning it into a module that exports its subroutines. But I am running into trouble. I think the trouble stems from a number reasons:

1. This file contains methods and functions that work together. For example, the do_this() method may change a scalar value in the function_call() subroutine.

2. This file is shared among separate files that are modules in themselves. So module A uses this file's new subroutine to create an object. And module B also uses this file for the same purpose. And module A then uses module B.

I am at my wit's end and don't know what's the best thing to do. Please help. :)

Replies are listed 'Best First'.
Re: Arcitectural considerations with modules
by kwaping (Priest) on Dec 30, 2005 at 02:44 UTC
    Sounds like quite a mess you've gotten yourself into!

    Can you provide some example code of item (1)? I think I understand what you're saying, but there's room for error and I'd like to be sure of what I'm discussing.

    As for item (2), what mechanism are you using to share this single file among modules A and B? require, I assume? If so, making the shared file into a module may provide some benefit, as the namespace would be distinct. Also, using use, it would be included at compile-time and only once, no matter how many use statments you have for it. That might provide a performance enhancement.
      The problem seems solved now that I put EVERYTHING into my export list as I should have before. Actually I don't like maintaining a large export list, so I was using my own custom import sub that combined the symbol tables. For example:
      sub import { my $pkg = shift; my $callpkg = caller(0); %{"$callpkg\::"} = (%{"$callpkg\::"}, %{"$pkg\::"}); }
      But this wasn't working out for some reason. I was so hopeful that it would work!
Re: Arcitectural considerations with modules
by Aristotle (Chancellor) on Dec 30, 2005 at 06:54 UTC

    This file contains methods and functions that work together. For example, the do_this() method may change a scalar value in the function_call() subroutine.

    Sounds like they should be methods on an object, so they can share state explicitly, instead of conceiling it behind hidden side effects.

    You’ll need to answer kwaping’s question before anyone can make a concrete suggestion, though. Your best bet is probably to post actual code (assuming it’s not huge).

    Makeshifts last the longest.

Re: Arcitectural considerations with modules
by sgifford (Prior) on Dec 30, 2005 at 06:34 UTC
    I think you'll need to give a small bit of sample code to demonstrate what your problem is; I'm understanding some of your general problems, but it won't be clear which solutions might help without knowing more details.

    The library file can export functions using Exporter, and another module can import them and they will be available as methods. It's not a problem if multiple modules all do this, and you can tell what class the method is called from by the first parameter passed in, which will be the name of the class. Here's some sample code:

    You can also re-export symbols you have imported, if you need to do that for some reason. Doing this along with inheritance should allow you to inherit both methods and library functions. For example:

    Generally, a Perl object will keep all of its data in a hash or array, so having do_this change a field in the object instead of a global variable might help some of your problems.

    Hope that's helpful!

Re: Arcitectural considerations with modules
by dragonchild (Archbishop) on Dec 31, 2005 at 21:38 UTC
    Move the methods into a base class and keep the functions in a module that uses Exporter and @EXPORT_OK. Then, any package that needs a function from the module can import it at will, separate from the methods in the base class.

    Now, something else you need to be aware of - if you have a base class, every "sub" in that base class can be treated as a method, regardless of whether it thinks of itself as a method or not. For example:

    package Functions; use base 'Exporter'; our @EXPORT_OK = qw( func1 ); sub func1 { ... } package Foo; use Functions qw( func1 ); sub new { bless {}, shift } # This is a method sub meth1 { my $self = shift; ... } package Bar; use base 'Foo'; package main; my $bar = Bar->new; $bar->func1();
    That will call func1() living in the Foo package with the first argument being $bar. Try it out if you don't believe me.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?