How can I import constants into multiple modules in Perl?
-
22-08-2019 - |
Question
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.
Solution
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?
OTHER TIPS
Check out Exporter and the perlmod
man page.
This chunk of code should do exactly what you want. Send all kudos to lkundrak.
package Constants;
use base qw/Exporter/;
use constant BOB => 666;
use constant ALICE => 555;
sub import {
no strict "refs";
${[caller]->[0].'::'}{$_} = ${__PACKAGE__."::"}{$_}
foreach grep { not /^(ISA|isa|BEGIN|import|Dumper)$/ }
keys %{__PACKAGE__."::"};
}
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.
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 ();