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

Its often the case that when i write a script, i'll break the code into multiple files that are required by the 'main' file. I'm talking about situations where some of the broken out files arent modules, but they're separated for helping keep the code organized. I think this is a pretty common practice.

Anyway, sometimes i'll want to use the same constants across many of these required libraries. Is the best way to do this to create a package with all the constants in it, export them, and use the constants package in all the support libraries that need them?

I guess this method seems a bit cluttered. Heres a simple example:

# file MyConstants.pm

package MyConstants; require Exporter; use base qw(Exporter); @EXPORT = qw(C1 C2); use constant C1 => 'blah'; use constant C2 => 'foo'; 1;
# file my_program.pl
#!/usr/bin/perl use MyConstants.pm require 'my_support_lib.pl'; ... # do something with the constants from MyConstants.pm ...
# file my_support_lib.pl
... use MyConstants.pm; ... # do something with the constants from MyConstants.pm ...
Is this a good way to accomplish this sort of thing?

Replies are listed 'Best First'.
Re: constants in multiple libraries
by davorg (Chancellor) on Sep 17, 2004 at 16:24 UTC

    That sounds like the best solution to me. In fact, I'd recommend _always_ using modules to break programs into more manageble chunks.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: constants in multiple libraries
by JediWizard (Deacon) on Sep 17, 2004 at 16:45 UTC

    It may just be my own personal prejudice, but I perfer not to ever require a .pl file. Whenever I move code out of the main script, I put it in a module (.pm) and use it.

    Another standard practice I have found helpfull is to always start a module with a package declaration, and simply export anything that may be needed in the client code. I have actually run into problems with modules that do not have a package declaration. See the blow example:

    #File Foo.pm sub make_foo { # do stuff } #File Bar.pm package Bar; use Foo; sub make_bar { &make_foo(); # It is defined here. # do stuff } #File myScript.pl #!/usr/local/bin/perl -w use strict; use Bar; use Foo; &make_foo(); # Undefined subroutine!

    Becuase Bar.pm was included before Foo.pm, Foo.pm was compiled into the Bar:: namespace and now &main::make_foo(); is an undefined subroutine. Not good.

    May the Force be with you
      Others may disagree with me on this, but for your example package Bar, id do the following instead:
      #File Bar.pm use Foo; package Bar; sub make_bar { main::make_foo(); # It is defined here. # do stuff }
      Because then, Foo is not part of Bar::, but part of main::, which is probably what you really want. I say this because it sounds like you want package Foo to be able to be used independently of Bar, so it shouldnt ever be tied strictly to Bar, because once it is, thats the only place it'll get put...unless you do some serious hand-waving.

        I have seen this approach taken before, so there are certainly people out there who will agree with you. However, the point I was trying to make is that Foo.pm should be a package of its own. If Foo.pm were package Foo; and exported &make_foo, then both Bar and main would have access to it without needing to fully qualify the package name.

        I feel that is is "sloppy" coding to refer to anything in the main namespace from inside an included package, because it violates encapsulation. When a package depends on methods or variables being defined in its client’s namespace, it becomes more difficult to accommodate. Explicitly referring to main from within a package is even worse because you might not be making assumptions about you're clients namespace, but rather your client's client's client's namespace. Such assumptions will make a code base unstable, and less extensible.

        May the Force be with you
Re: constants in multiple libraries
by ikegami (Patriarch) on Sep 17, 2004 at 16:31 UTC

    Update: Forgot to export C3 when testing X_X. Not only does every syntax work with Exporter, further testing with perl -MO=Debug showed me that constant folding *does* apply with Exported constants.

    Yes, putting them in a module is a great idea. However, constants are special, and they won't work as expected the way you have the module coded.

    use c1; print(&C1, C2(), C3, "\n"); # blahfoobar BINGO! do "c2.pm"; print(&C4, C5(), C6, "\n"); # blahfooC6 PARTIAL FAIL! BEGIN { do "c3.pm"; } print(&C7, C8(), C9, "\n"); # blahfoobar BINGO! c1.pm ===== package c1; require Exporter; use base qw(Exporter); @EXPORT = qw(C1 C2 C3); use constant C1 => 'blah'; use constant C2 => 'foo'; use constant C3 => 'bar'; 1; c2.pm ===== use constant C4 => 'blah'; use constant C5 => 'foo'; use constant C6 => 'bar'; c3.pm ===== use constant C7 => 'blah'; use constant C8 => 'foo'; use constant C9 => 'bar';

    That's because Exporter loses the magic that constantss have. Exported constants are not inlined in the importing module, and therefore are not subject to constant folding optimization. That is, unless you use do() at compile time to emulate a C/C++ #include.

      The first version will work if you also export C3

      Well it worked for me on:
      perl -v
      This is perl, v5.8.0 built for i386-linux-thread-multi ...