tags:

views:

693

answers:

4

I have a bunch of Perl files which take in some filename constants. I would like to define these in a separate file - something like a header file in C. What's the best/most standard way of doing this in Perl?

A: 

One way would be to write them as a perl module, that you can subsequently include with "require" or "use". You'd write your file like this -- give it a .pm extension (e.g., myFabulousPackage.pm)

package myFabulousPackage;

$someSetting=45;
$otherSetting='Fish';

1;

Then in your perl script, this would include the file and then reference $otherSetting:

#!/usr/bin/perl

use myFabulousPackage;

print $myFabulousPackage::otherSetting;

This is just a very simple view of what you can do with a package/module, but for what you need, this might be the simplest way to implement it. Similarly, you can put sub's in the package as well, and reference them in a similar way.

Chris J
This won't work. Variables declared with my (lexical variables) are not accessible via `$PackageName::varname`. This syntax only accesses variables in the symbol table. The best way to put variables in the symbol table is to use `our` to declare them.
daotoad
That won't actually work. The `my` declaration of the variables makes them lexically scoped, and thus only visible to code in the `.pm` file. You want them to be declared with `our` instead. Also, it's a good idea to always terminate module files with `1;` because if the last statement somehow evaluates to a false value, the module won't load.
arnsholt
Yep -- you're right about the 'my' ... that's me writing perl on auto-pilot, and not double checking my examples. Edit'd.
Chris J
Chris J: you can use "our" instead of "my"
Alexandr Ciornii
Please use "use strict; use warnings;", which will prevent you from implicitly declaring new variables. You should always use either "our" or "my", which these pragmas will enforce.
Ether
+6  A: 

We usually do this with a module name Constants. Something like:

package MyPackage::Constants;

our $DIR = "/home/chriss";
our $MAX_FILES = 5;

1;

Then, to use it:

package MyPackage;
use MyPackage::Constants;

open(my $fh, ">", $MyPackage::Constants::DIR . "/file");

If you didn't want to reference the package all the time, you could use Exporter and bring in all the symbols you want.

Chris Simmons
Why not define the MyPackage constants in the MyPackage module itself, rather than making a new namespace? And if you refer to the constant as namespace::DIR, you lose the advantage of inheritance, i.e. MyPackage::Child::Constants can't inherit from MyPackage::Constants and override the value of DIR. namespace->DIR is much better.
Ether
This is a simplistic example for illustrative purposes. That said, not everything is OO :)
Chris Simmons
That looks like configuration, not constants.
brian d foy
Also, why declare these as variables rather than constants? See http://perldoc.perl.org/constant.html as Sinan's post describes.
Ether
brian d foy's right, this is configuration. However, in the work I do there are very few "constant" constants (no math stuff, etc.), so most of what I do is configuration.
Chris Simmons
+5  A: 

This sounds like configuration settings, which would be better put in a config file that you parse with one of the various CPAN modules, for instance Config::Any.

Configuration is data, which IMO shouldn't be in your code.

David Precious
+7  A: 

There is no equivalent to C header files in Perl. To declare and define global constants, you can use the define pragma. I have no experience with this module although the interface seems sensible.

On the other hand, you can write a module where you define constants and import them into your module using use. For example:

package MyConstants;

use strict; use warnings;

use base 'Exporter';

use Readonly;

our @EXPORT = qw();
our @EXPORT_OK = qw( $X $Y );

Readonly::Scalar our $X => 'this is X';
Readonly::Scalar our $Y => 'this is Y';

1;

You can then use this module as follows:

#!/usr/bin/perl

use strict; use warnings;

use MyConstants qw( $X );

print "$X\n";
print "$MyConstants::Y\n";

If you are OK with using fully qualified variable names (e.g. $MyConstants::Y), you do not need Exporter at all.

Also, make sure variables you export are not modifiable elsewhere (see the caution in Exporter docs).

Of course, you could also define constants using constant.pm. It is faster to use such constants, but they are awkward if you need to interpolate them in a string.

Sinan Ünür
Readonly::Scalar is pretty fast as well if you have Readonly::XS installed. Hashes and Arrays are still slower though.
Chas. Owens
Note that the exporter docs ( http://perldoc.perl.org/Exporter.html ) recommend that you do NOT export variables, even though it lets you.
Robert P
@Robert P, IMO exporting a variable on request is reasonable, exporting one (or more!) by default is best avoided. If in the example above, I was expecting to use $X many, many times and wanted to avoid the needless repetition of typing `$MyConstants::X` everywhere, it would be a huge benefit. Another case for imported variables is that if I accidentally tried to use `$MyConstants::x`, no `strict` generated error message would alert me to my error, whereas, if I import `$X` and try to use `$x`, strict saves the day by catching the error.
daotoad
I'll buy that. I generally use the `use constant` form, and export those. If I were using the Readonly package, that would probably make logical sense.
Robert P
@Robert P: The variables that are exported in this case are not modifiable (and my answer links to the warning in the docs about exporting variables).
Sinan Ünür