tags:

views:

938

answers:

4

I'm writing an app in Perl with several modules. I want to write some global constants that will be visible from everywhere, like this:

#Constants.pm
$h0 = 0;
$scale = 20;

And then use them without qualifying with main:: or Constants:: in several modules. However, if I write use Constants; in more than one module, they only get imported into one namespace. Is there any way around this?

I'm using the latest ActivePerl.

A: 

You can put this at the top of Constants.pm:

package main;

In this case all the variables you define will be in the main namespace:

$main::x

or if you're feeling brave:

package;

In this case all the variables you define will be in an empty namespace:

$::x

Note that using package with no namespace is discouraged, and will apparently be deprecated in some versions of Perl. See the quote below.


Quoting from man perlfunc:


       package NAMESPACE
       package Declares the compilation unit as being in the given
               namespace.  The scope of the package declaration is
               from the declaration itself through the end of the
               enclosing block, file, or eval (the same as the "my"
               operator).  All further unqualified dynamic identifiers
               will be in this namespace.  A package statement affects
               only dynamic variables--including those you've used
               "local" on--but not lexical variables, which are cre?
               ated with "my".  Typically it would be the first decla?
               ration in a file to be included by the "require" or
               "use" operator.  You can switch into a package in more
               than one place; it merely influences which symbol table
               is used by the compiler for the rest of that block.
               You can refer to variables and filehandles in other
               packages by prefixing the identifier with the package
               name and a double colon:  $Package::Variable.  If the
               package name is null, the "main" package as assumed.
               That is, $::sail is equivalent to $main::sail (as well
               as to $main'sail, still seen in older code).

               If NAMESPACE is omitted, then there is no current pack?
               age, and all identifiers must be fully qualified or
               lexicals.  However, you are strongly advised not to
               make use of this feature. Its use can cause unexpected
               behaviour, even crashing some versions of Perl. It is
               deprecated, and will be removed from a future release.


Edit: This question might be helpful as well: How do I use constants from a Perl module?

Nathan Fellman
Thanks. What I really needed is the piece about omitting "main".
Lev
I'm curious if it actually works. If it does, I'll remove the disclaimer at the top of the answer.
Nathan Fellman
This puts the constants in main::, but now you have to prefix all the constants with main::
brian d foy
Nathan: It works.Brian: No, you only have to prefix them with $::. That's tolerable.
Lev
FWIW, Perl 5.10 refuses to parse "package;".
jrockway
Why is using $:: better than exporting the variables into the current namespace? I'm just curious....
Joe Casadonte
Probably not. Lev just said it's tolerable. Lev, you might want to consider using Exporter as Joe Casadonte suggests.
Nathan Fellman
+7  A: 

Check out Exporter and the perlmod man page.

Joe Casadonte
+2  A: 

Don't tell anyone I told you this, but Perl's special variables are available everywhere. You have probably noticed that this doesn't work:

{ package Foo;
our $global = 42; }

{ package Bar;
say "global is $global"; }

That's because $global is actually called $Foo::global. You've also probably noticed that this "rule" doesn't apply to things like @INC, %ENV, $_, etc. That's because those variables are always assumed to be in main.

But actually, it's more than just those variables. The entire glob gets "forced" into main. That means you can write something like this:

{ package Constants;
  $_{PI} = 3.141592; }

{ package Foo;
  say "pi is $_{PI}"; }

and it will work.

(The same applies for $ENV, &INC, etc.)

If you ever do this in real code, however, expect someone to murder you :) It is good to know, though, just in case you see someone else doing it.

jrockway
+1  A: 

You can use Exporter like this:

In Constants.pm:

#Constants.pm
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw($h0 $scale);
@EXPORT_OK = qw(myfunc);

$h0 = 0;
$scale = 20;
sub myfunc {...}

Notes:
* the & in &myfunc in the @EXPORT array is optional, and it's recommended you don't use it. * This will export $h0 and $scale by default, and &myfunc only if it's requested explicitly (see below how to specify which symbols are imported by the client module)

And then in the module that imports Constants.pm and wants to use $h0, $scale or &myfunc you add the following to import all of the symbols that are in @EXPORT in Constants.pm.

#MyModule.pm
use Constants qw(;

If you want to import only some of the symbols use:

#MyModule.pm
use Constants qw($h0);

And finally, if you don't want to import any of Constant.pm`s symbols use:

#MyModule.pm
use Constants ();
Nathan Fellman