smith
smith

Reputation: 3262

initialize constant variable with perl

I have the following constant :

use constant => 7

is there an option to set the constant by a scalar variable once and then the value of the constant will be the initialized value i.e somthing like this :

use constant => $scalar -> then the constant from now have the value of scalar on this point

any suggestion ?

Upvotes: 2

Views: 1047

Answers (3)

David W.
David W.

Reputation: 107030

Constants are created at compile time by creating a subroutine that returns the value of the constant.

For example:

 use constant PI => 3.1415169;

Is similar to this:

sub PI {
    return 3.1415169;
}

The problem is that constants are hard to use in various situations like regular expressions or in quoted strings. There is a secret, obscure way of interpolating the constant (and this method works for other types of subroutines too. You can embed the constant inside @{[...]}:

say "The value of pi is equal to @{[PI]}.";

# Replace value of Pi in Alabama: http://www.snopes.com/religion/pi.asp

$foo = s/@{[PI]}/3/g;

Ugly isn't it?

Another way is to use type globs:

*PI = \3.1415926;
our $PI;

This interpolates:

say "The value of pi is $PI."

But, doesn't work so well with anything other than scalars. You can define arrays and hashes, but they're not constant values.

Fortunately, there are myriads of ways to define constants that act more like variables. Unfortunately, there are myriads of ways to define constants that act more like variables and there's no standard module that comes with Perl does it. This means that you have to install some optional CPAN module on each system where you need to run your script. If these are on corporate servers, you'll probably need someone to install the module for you.

Plus, since everyone has their own favorite constant routine, you'll probably end up installing multiple modules:

The most popular one is Readonly:

use Readonly;

# For Perl 5.8 and later...
Readonly my $pi => 3.1415926;

It's fast and simple, but Readonly can be slow unless you also install Readonly:XS too, and Readonly::XS can be difficult to install if you don't have a C compiler and Make. A newer module called Const::Fast is also fairly popular:

use Const::Fast;
const my PI => 3.1415926;

say "The value of pi is $pi.";

So, there you have it.

  • You can use use constant; which is a standard module, so you know it's always available. However, it doesn't interpolate very easily. You can use the @{[...]} syntax, but it's ugly.
  • You can use typglobs which work in almost any version of Perl and doesn't need an optional module. Typeglobs do interpolate, but the definition syntax is just hideous. Plus, they don't work well for arrays and hashes.
  • You can use Readonly or Const::Fast, but you must install them via CPAN before your script will run which can be difficult in certain situations.

Upvotes: 2

ikegami
ikegami

Reputation: 385496

Yes, you can. Of course, you must assign the value to the scalar soon enough.

my $foo;
BEGIN {
   ...
   ...
   $foo = ...;
}
use constant FOO => $foo;

You could also use do.

use constant FOO => do {
   ...
   ...
   ...
};

Upvotes: 4

amon
amon

Reputation: 57590

Constants created with use constant are processed at compile time, so that $scalar variable will likely not have any value assigned yet.

You can however use the Const::Fast module to make a scalar – well – constant:

use Const::Fast;

my $scalar = 7;
const my $constant => $scalar;
$constant = 42; # dies

This is preferable to use constant anyway as it's nicer to handle const scalars than it is to handle constants (which are implemented as special subroutines). For example, a const scalar can be interpolated into a string.

However, compile-time constants take part in the constant folding optimization. There are some cases where this is actually necessary, so some use for use constant remains.

(If you can't use Const::Fast, then Readonly is another option, although slower)

Upvotes: 7

Related Questions