http://www.perlmonks.org?node_id=452043

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

I am working on a program that has several hundred constants and I'm trying to figure out a good way to include those via a required file or a used module. I've run into problems and looking for advice.

If I require a file full of constants in g1.inc like

use constant FAILURE_CONF => 1; use constant FAILURE_EVENT => 2; use constant OPEN_REQ => 3; use constant OPEN_CONF => 4; 1;
And use it like

use strict; require "g1.inc"; if ( 3 == OPEN_REQ ) { print "Code is OPEN_REQ\n"; } else { print "Code is NOT OPEN_REQ\n"; }

I receive: 'Bareword "OPEN_REQ" not allowed while "strict subs"'. I had thought for some reason requiring a file is like inserting that code at that spot in the script. Is it a compiletime vs runtime issue?

If I use a module, what is the briefest way to pass my large number of declared constants into the main namespace without retyping everyone of them into @EXPORT?

I await your witty wisdom. :-)

Replies are listed 'Best First'.
Re: How to include a large number of constants?
by dragonchild (Archbishop) on Apr 27, 2005 at 17:49 UTC
    Yes, it is a compile-time vs. run-time issue. You could enclose your require statement in a BEGIN{} block and do just fine.

    As for your second question, you could have all your constants have a common prefix, like C_. Then, you can do a little introspection as so:

    package Constants; use base 'Exporter'; our @EXPORT = grep { substr( $_, 0, 2 ) eq 'C_' && __PACKAGE__->can( $_ ); } keys %Constants::; use constant C_FOO => 1; use constant C_BAR => 2; use constant C_BAZ => 3;

    The Perfect is the Enemy of the Good.

      ++ to the last three answers!    I am currently in need of just this type of thing.
      I'm out of votes today, and needed a 'bookmark' here to remember to come back tomorrow...

      -Scott

      This is actually very cool:
      package Constants; use base 'Exporter'; our @EXPORT = grep { substr( $_, 0, 2 ) eq 'C_' && __PACKAGE__->can( $_ ); } keys %Constants::;
      The way I used to do it was to essentially use a source filter: I'd have a BEGIN block inside my Definitions.pm file read the file itself in and look for "use constant" lines:
      Constant Amusement (auto export trick)

      Anyone doing a lot of work with perl constants might want to skim through those talk notes, by the way. And in general, these days I'd recommend staying away from constants altogether -- their utility rarely makes up for their annoyances (e.g no sigil, so they don't interpolate very smoothly). Also a case can be made for keeping definitions of things in a YAML file instead of using perl code to store configuration (programmatic modification of YAML is a lot easier than parsing perl).

Re: How to include a large number of constants?
by Zaxo (Archbishop) on Apr 27, 2005 at 17:44 UTC

    require is to happen at runtime, which leaves the compiler with a bareword and nothing to match in the symbol table. Arrange to use the file instead, since that happens at compile time.

    After Compline,
    Zaxo

Re: How to include a large number of constants?
by BrowserUk (Patriarch) on Apr 27, 2005 at 17:44 UTC

    do file is probably the simplest way. Otherwise, you have to arrange for them to be exported from the modules namespace into the callers.

    do 'g1.inc';

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco.
    Rule 1 has a caveat! -- Who broke the cabal?
      I tried using "do 'g1.inc';" but I get the same results as require with the bareword warning...

        For the constant subs to be recognised as such when the code that calls them is compiled, you'll need to put the do in a BEGIN{} block.

        BEGIN{ do 'gi.inc'; }

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco.
        Rule 1 has a caveat! -- Who broke the cabal?
Re: How to include a large number of constants?
by jhourcle (Prior) on Apr 27, 2005 at 18:15 UTC

    I cheat, personally. I have a program which loads all of its contents from an XML file.

    I think I've got this down the bare minimum required to be a useful example. (there's a few different type of config parameters, not all of which get exported, and logic for adding new values)

    Update: You'd of course want to swap EXPORT_OK and EXPORT, so you don't have to pass in which constants you wanted to import (also cleaned up a typo, and split a paragrah)

Re: How to include a large number of constants?
by holli (Abbot) on Apr 27, 2005 at 18:26 UTC
      Wow, that distribution is a poster-boy for how to (ab)use Module::Build. The author creates his modules on the fly during the build process, which is kinda nuts. More importantly, he pre-generates a list of constants ahead of time, then the modules end up explicitly listing every constant. The resulting files are going to look ... well ... ugly.

      Now, the process the author uses is kinda nice. Maybe that should be replicated, but definitely not the resulting code.


      The Perfect is the Enemy of the Good.

Re: How to include a large number of constants?
by Grygonos (Chaplain) on Apr 27, 2005 at 18:00 UTC

    Try this..

    use constant {FAILURE_CONF => 1, FAILURE_EVENT => 2, OPEN_REQ => 3, OPEN_CONF => 4};
    Should simpllify the code a bit, visually speaking.

Re: How to include a large number of constants?
by perrin (Chancellor) on Apr 27, 2005 at 17:43 UTC
    Make your g1.inc into an actual module with a package name and then just reference them with fully-qualified names, e.g. MyConstants::OPEN_REQ().
Re: How to include a large number of constants?
by noslenj123 (Scribe) on Apr 27, 2005 at 21:20 UTC
    Thanks for all your suggestions. I have put several of them to use.

    perrin's suggestion works fine, but adds verbosity.

    Using 'do' didn't seem to help and gave me the same error.

    zaxo confirmed the compiletime issue.

    Thus, dragonchild's suggestion for using BEGIN worked fine. Also, I really like his wizardry for getting all the constants into @EXPORT without typing them all. I incorporated that technique. Thanks!

    I also used Grygonos's suggestion simplifying the creation of all the constants.

    I'm gonna need to spend some time studying jhourcle's XML technique.

    friedo's technique looks similar to dragonchild's but I didn't have enum.pm installed so haven't checked it out yet.

    I have learned many lessons o wise ones!

Re: How to include a large number of constants?
by friedo (Prior) on Apr 27, 2005 at 19:09 UTC
    At a previous job I used enum and a bit of symbol-table trickery:

    package Constants; use base 'Exporter'; use enum qw(:C_ FOO, BAR, BAZ); our @EXPORT = grep /^C_/, %{__PACKAGE__ . "::"}; 1;
Re: How to include a large number of constants?
by sir.shz (Novice) on Apr 27, 2005 at 18:11 UTC
    I'll just put them in a separate module:
    package Constants; use strict; use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(FOO $BAR @A %H) use constant FOO => 1; our $BAR = "bar"; our @A = (1,2,3,4); our %H = (a=>1,b=>2); 1;
    Then in your main script:
    use strict; use Constants; print FOO,"\n"; print $BAR,"\n"; print join(",",@A),"\n"; print "$_=>$H{$_}," foreach keys %H;
      Of course that is normally what I do. But I will have several hundred of your F00's and don't want to type them all into @EXPORT.
Re: How to include a large number of constants?
by phaylon (Curate) on Apr 27, 2005 at 20:59 UTC
    How about organizing them with %EXPORT_TAGS? You cou then just say
    use MyModule qw(:group1 :group2);
    It should also be possible to pack smaller groups together in larger ones.

    Ordinary morality is for ordinary people. -- Aleister Crowley
Re: How to include a large number of constants?
by salva (Canon) on Apr 27, 2005 at 17:46 UTC