http://qs321.pair.com?node_id=455347

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

I have a desire to do something like this.

In file MyPackage.pm:

package MyPackage; our @Settings; sub whatever { # Use any externally supplied settings. print join("\n", @Settings), "\n"; }

In file MyConfig.pm:

package MyConfig; # Set up code goes here ... # Now switch to the other package and set values package MyPackage; our @Settings = (qw/a ab cdef ghi/);

It seems to work fine, but it seems a little evil (maybe that's making it more attractive :-). The reason for wanting to do this beyond the contrived example is this: I have some modules that do preliminary run-time set up based on environment, etc. That would be the role of the MyConfig.pm file in the example. These modules need to set up without invoking the actual packages that depend on what they set up -- it's a classic bootstrap/chicken-egg sort of problem. In other words, MyConfig may set values that change the way MyPackage gets invoked (or even where it gets invoked from). If I provide a nice interface in MyPackage, then MyConfig has to use MyPackage to use that interface, defeating the purpose of having preliminary set-up. On the other side, having MyPackage have to know to call out to a preliminary set-up package to pull set-up values in also seems like bad interface design -- I'd prefer to have the package do what it does and not have to worry about add-ons that change its behavior. In this specific sort of case, I'm extending the package interface to a pretty general "if you put something in here, no matter how you do it, I will use it" model.

What are opinions on doing this sort of thing, or ideas for not doing it? I'm also not sure if having an our declaration in two places is strictly kosher or if I'm just lucking out that it works. Maybe leaving our off is better practice in a case like this?

Replies are listed 'Best First'.
Re: package splitting and 'our' use
by scmason (Monk) on May 09, 2005 at 22:49 UTC
    I get knocked for not being 'perlish' enough, but I am going to throw my two-cents in anyway:

    It seems like switching namespaces would always be a bad idea (confusion, readablility, tracablility etc). While this might be a quick way out of a design-time roadblock, I think you are on the right track when you say "I'd prefer to have the package do what it does and not have to worry about add-ons that change its behavior"

    You might consider if there are some minor refactoring to other parts of your project that can could suggest a better design.

    With that said, sometimes we have to remember that it is not a perfect world and we have to make things work no matter what it takes.

    Good luck.

Re: package splitting and 'our' use
by saintmike (Vicar) on May 09, 2005 at 22:59 UTC
    Having MyConfig.pm mock with MyPackage is probably better done by using
    use MyPackage qw(:sometag);
    and have MyPackage's import() function deal with it and do something meaningful with it.

      This approach forces the preliminary "bootstrap" configuration package to include modules that depend on it. Suppose, for example, that part of the configuration set up is to use different package @INC paths to pull in different code trees based on environment (development versus production, etc.). Having to use the packages the configuration is trying to affect means that they may get pulled in too soon, rendering the configuration piece useless for those packages. It's your classic chicken/egg problem. My goal is to write these configuration pieces so they're as independent of the rest of the code as possible, thereby allowing them to set things up that affect the rest of the run-time environment without having to hook into those run-time packages too deeply. They're very much like shell level environment settings in that regard.

Re: package splitting and 'our' use
by thcsoft (Monk) on May 10, 2005 at 03:31 UTC
    i think, what you like to achieve could be easier realized this way:
    package MyConfig; use strict; use vars qw/@settings/; # now fill in values in the setings list. ...
    and then:
    package MyModule; use strict; our @settings; *settings = \@MyConfig::settings; ...
    that's at least the way i'm doing it, but it works perfectly well. btw: wouldn't a hashtable be a better approach?

    language is a virus from outer space.

      I considered this approach. What I don't like about it is that it forces every package the set-up affects to know about the set-up. I'd rather keep the set-up hidden, writing the packages to use things without worrying about where they come from.

      The use of an array for settings was only for illustration purposes. The real implementation of this would be using different data structures; primarily hashes.