4

I'm trying to make it easier to follow some Perl Best Practices by creating a Constants module that exports several of the scalars used throughout the book. One in particular, $EMPTY_STRING, I can use in just about every Perl script I write. What I'd like is to automatically export these scalars so I can use them without defining them explicitly in each script.

#!perl
package Example::Constants;

use Exporter qw( import );
use Readonly;

Readonly my $EMPTY_STRING => q{};
our @EXPORT = qw( $EMPTY_STRING );

An example usage:

#!perl
use Example::Constants;
print $EMPTY_STRING . 'foo' . $EMPTY_STRING;

Using the above code produces an error:

Global symbol "$EMPTY_STRING" requires explicit package name

If I change the Readonly declaration to:

Readonly our $EMPTY_STRING => q{}; # 'our' instead of 'my'

The error becomes:

Attempt to reassign a readonly scalar

Is this just not possible with mod_perl?

RobEarl
  • 7,862
  • 6
  • 35
  • 50
cowgod
  • 8,626
  • 5
  • 40
  • 57

3 Answers3

4

You had 4 problems:

  1. You weren't including the strict and warnings pragmas
  2. It is better to include exporter through the base pragma (since it sets @ISA for you)
  3. Only package variables (i.e. our variables) can be exported
  4. Modules must end with a true value

Here is the corrected module.

package Example::Constants;

use strict;
use warnings;
use base 'Exporter';
use Readonly;

Readonly our $EMPTY_STRING => q{};
our @EXPORT = qw( $EMPTY_STRING );

1;

Hmm, I missed the bit about attempting to assign to a readonly, it sounds like the module is getting loaded more than once. I believe mod_perl has a mechanism for loading modules separate from the scripts themselves. This loading happens only once, so you should be using it.

Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
  • I'm already doing 1, 3 and 4, I just left them out of the example for brevity. Also, use Exporter qw( import ) is the preferred method, not use base qw( Exporter ). Adding the module to PerlRequire still produces the error, one for each http process started. – cowgod Apr 10 '09 at 19:17
  • Also, did you remove "use Example::Constants;" from your script? – Chas. Owens Apr 10 '09 at 19:40
  • This works for me as-is! Perhaps you could include the code using it from the question as well, for completeness: use Example::Constants; print $EMPTY_STRING . 'foo' . $EMPTY_STRING; –  Aug 19 '14 at 21:41
4

I'm the author of the Readonly module. The next version of Readonly will provide support for mod_perl, specifically because of this problem.

I know this doesn't solve your problem now, but... well, I'm working on it :-)

-- Eric

1

I don't have a mod_perl instance handy to test with, so I can't test these suggestions. I hope they pan out.

Try using Scalar::Util::readonly to check if the variable has already been marked read only.

#!perl
package Example::Constants;

use Exporter qw( import );
use Readonly;
use Scalar::Util qw(readonly);

our $EMPTY_STRING;
our @EXPORT = qw( $EMPTY_STRING );

if ( !readonly( $EMPTY_STRING ) ) {
    Readonly $EMPTY_STRING => q{};
}

You could also try use vars:

#!perl
package Example::Constants;

use Exporter qw( import );
use Readonly;
use vars qw( $EMPTY_STRING );

Readonly $EMPTY_STRING => q{};
our @EXPORT = qw( $EMPTY_STRING );

You could also use a typeglob constant:

#!perl
package Example::Constants;

use Exporter qw( import );
use Readonly;

our $EMPTY_STRING;
*EMPTY_STRING = \q{};
our @EXPORT = qw( $EMPTY_STRING );

Using a typeglob constant seems perfect, since the big limitation of the technique (it requires a package global) is not an issue here.

daotoad
  • 26,689
  • 7
  • 59
  • 100