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

In a sense, our and @Exporter::EXPORT serve a similar purpose. They allow for the use of certain package symbols without package qualification. I would like to know how I can "our" and "@EXPORT=" a set of variables in a clean and concise fashion. Current code of someone else I am revising below:
use strict; use Exporter; package Base; my @var = qw( $MC_CONFIG_DBI_DRIVER $MC_CONFIG_DB_NAME $MC_CONFIG_DB_USER $MC_CONFIG_DB_PWD $MC_CONFIG_FILE $MC_CONFIG_FEED_LOGS $MC_CONFIG_ARCHIVE_LOGS ); # FAILS ALSO { no strict 'refs'; map { our $$_ } @var; } use vars @var; # FAILS our @ISA = qw(Exporter); # WORKS our @EXPORT = @var;

Replies are listed 'Best First'.
Re: How to set a set of our and @EXPORT variables concisely?
by chromatic (Archbishop) on Nov 20, 2000 at 22:30 UTC
    Hmm, your coworker is exhibiting false laziness. While I normally agree with building an array (not a list) of variable names, I usually use it in a hash slice.

    As far as I understand it, you need to declare variables first, then export them, under strict:

    our ($MC_CONFIG_DBI_DRIVER, $MC_CONFIG_DB_NAME, $MC_CONFIG_DB_USER, $MC_CONFIG_DB_PWD, $MC_CONFIG_FILE, $MC_CONFIG_FEED_LOGS, $MC_CONFIG_ARCHIVE_LOGS ); our @ISA = qw( Exporter ); our @export = ($MC_CONFIG_DBI_DRIVER, $MC_CONFIG_DB_NAME, $MC_CONFIG_DB_USER, $MC_CONFIG_DB_PWD, $MC_CONFIG_FILE, $MC_CONFIG_FEED_LOGS, $MC_CONFIG_ARCHIVE_LOGS );
    Using symbolic references to avoid a simple cut-and-paste (especially as it's actually *appropriate* in this case) is a punishable offense.

    One more thing, your coworker is a little confused on the difference between a list and an array:

    our vars = ($one, $two, $three); # a list our vars @array; # an array and an error
(tye)Re: How to set a set of our and @EXPORT variables concisely?
by tye (Sage) on Nov 21, 2000 at 02:02 UTC

    I'd just go with the use vars approach. Your only mistake was not initializing your variables at compile time. This is a very common mistake and is often misdiagnosed.

    use base qw( Exporter ); our @EXPORT; BEGIN { @EXPORT= qw( $MC_CONFIG_DBI_DRIVER $MC_CONFIG_DB_NAME $MC_CONFIG_DB_USER $MC_CONFIG_DB_PWD $MC_CONFIG_FILE $MC_CONFIG_FEED_LOGS $MC_CONFIG_ARCHIVE_LOGS ); } use vars @EXPORT;

    You see, in your original code, the my @var declares the @var array at compile time but doesn't initialize it (fill it with values) until run time. But use vars happens at compile time so you end up passing use vars an empty array.

    The our trick can only half work since the "create lexical alias" part of our only has effect until the end of the current scope. So your map might be able to declare a bunch of package globals for you but the lexical aliases to them would disappear at the end of the enclosing block (either the block in the map statement or the next one -- I'd have to test to say for sure). But to get that to work probably requires eval, which also forces an enclosing block so there is no way to script doing our on a list of variable names unless you want to enclose almost your entire module inside an extra eval.

            - tye (but my friends call me "Tye")
      There we go! Thanks tye. I knew it could be done and thank you for showing how it can be done.

      The only problem is: supposedly use vars is deprecated so this example must use our to remain viable in years to come. So, to use our, I guess we have to use eval

      use base qw( Exporter ); our @EXPORT; BEGIN { @EXPORT= qw( $MC_CONFIG_DBI_DRIVER $MC_CONFIG_DB_NAME $MC_CONFIG_DB_USER $MC_CONFIG_DB_PWD $MC_CONFIG_FILE $MC_CONFIG_FEED_LOGS $MC_CONFIG_ARCHIVE_LOGS ); eval "our $_;" for @EXPORT; }

        But as you found out, the our declares a global variable but the lexical alias to it goes away when you leave the enclosing scope (either the eval or the BEGIN, I'm not absolutely sure which and it would be hard to test but it doesn't really matter here).

        So you still have to fully qualify the variable name in the rest of your script. As I already said, there is no good fix for this other than use vars.

        I see no mention of use vars being depricated. The closest thing I found was "NOTE: The functionality provided by this pragma has been superseded by `our' declarations". Since using our makes your script not work on even very slightly old versions of Perl, there will still be many scripts using use vars for quite a long time. So deleting vars.pm would be quite stupid of the perl porters, especially since it would be impossible to write version-portable code via something like:

        BEGIN { if( 5.6 < $^V ) { eval 'our $x; 1' or die $@; } else { require vars; vars->import( '$x' ); } }
        for the exact same reasons that our doesn't work for your code.

        So don't worry about vars.pm going away until you actually read that is has been deprecated (not "superseded").

        Note that our makes for slightly more efficient code, and this is probably why the use vars documentation points you in that direction a little strongly. This efficiency is pretty trivial so I wouldn't sacrifice maintainability (by having two lists of variables to keep in sync) for it.

                - tye (but my friends call me "Tye")
      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: How to set a set of our and @EXPORT variables concisely?
by merlyn (Sage) on Nov 21, 2000 at 01:53 UTC
    I'm confused about your design. Are you exporting a large number of variables because they are constants needed for an interface? If so, you should be exporting functions created with use constant instead.

    If instead you expect many other modules to mangle variables directly in your namespace, you are asking for trouble in maintenance. Don't make me maintain your code once you've done that. If someone gave me that code to maintain, I'd probably start by rewriting it to introduce interface subroutines for everything.

    Export functionality, not data. Learn at least something from the OO movement.

    -- Randal L. Schwartz, Perl hacker

Re: How to set a set of our and @EXPORT variables concisely?
by mwp (Hermit) on Nov 20, 2000 at 22:37 UTC
    I must admit that I am rather confused to what you are asking. our is for declaring global variables in a Perl script. It has depreciated use vars qw(global variable list). Defining @EXPORT says which functions and variables should be exported from a Perl module by default. The two seem to be radically different to me, but maybe I am missing something?

    At any rate, you should read perlman:lib:Exporter, perlman:perlmodlib and perlman:perltoot for a better idea of how Perl's OO works. Particularly with regards to exporting variables from a package.

    For the second part, using our to define global variables from a list of variable names... you might want to read my post References of Eternal Peril (and it's resultant list of extremely helpful and informative replies) for some help with that. AFAIK there's no way to do it using our.

    Alakaboo
    "Who gave HIM a Perl interpreter?!"

    A reply falls below the community's threshold of quality. You may see it by logging in.