NAME
Acme::constant - Like constant, except actually not.
SYNOPSIS
use Acme::constant ACME => 42;
print "ACME is now ", ACME, ".\n";
ACME = 84;
print "But now, ACME is ", ACME, "\n";
use Acme::constant LIST => 1, 2, 3;
print "Second element of list is ", (LIST)[1], ".\n";
(LIST) = (4, 5, 6);
print "But now, the second element is ", (LIST)[1], "\n";
DESCRIPTION
This pragma lets you make inconstant constants, just like the constants the users of Ruby or Opera (before Opera 14, that is) already enjoyed.
Unlike Perl constants, that are replaced at compile time, Acme constants, in true dynamic programming language style, can be modified even after declaration.
Just like constants generated with standard use constant
pragma, the constants declared with use Acme::Constant
don't have any sigils. This makes using constants easier, as you don't have to remember what sigil do constants use.
NOTES
As the Perl compiler needs to know about which barewords are keywords, constants have to defined in BEGIN
section. Usually, this is not a problem, as use
statement is automatically put in implicit BEGIN
section, but that also means you cannot dynamically create constants. For example, in the example below, the DEBUG
constant is always created, with value 1, as use
is processed when Perl parser sees it.
if ($ENV{DEBUG}) {
use Acme::constant DEBUG => 1; # WRONG!
}
It's possible to dynamically use this module using if module, however, this is likely to cause problems when trying to use constant that doesn't exist.
use if $ENV{DEBUG}, Acme::constant => DEBUG => 1;
You can also use directly use import
method, in order to conditionally load constant.
BEGIN {
require Acme::constant;
Acme::constant->import(DEBUG => 1) if $ENV{DEBUG};
}
Howver, usually the good idea to declare constant anyway, as using undefined constants in strict mode causes Perl errors (and sometimes could be parsed incorrectly).
use Acme::constant DEBUG => $ENV{DEBUG};
Constants belong to the package they were defined in. When you declare constant in some module, the constant is subroutine declared in it. However, it's possible to export constants with module such as Exporter, just as you would export standard subroutine.
package Some::Package;
use Acme::constant MAGIC => "Hello, world!\n";
package Some::Other::Package;
print Some::Package::MAGIC; # MAGIC directly won't work.
List constants
Just like standard constant module, you can use lists with this module. However, there are few catches you should be aware of.
To begin with, you cannot use list constants in scalar context. While constant module lets you do this, I believe allowing something like this can open can of worms, because constant with one element is just as valid constant (that wouldn't return 1). Something like this won't work.
use Acme::constant NUMBERS => 1..6;
print 'Found ', scalar NUMBERS, " numbers in NUMBERS.\n"; # WRONG!
Instead, to count number of elements in the constant, you can use the () =
trick, that lets you count elements in any sort of list.
use Acme::constant NUMBERS => 1..6;
print 'Found ', scalar(() = NUMBERS), " numbers in NUMBERS.\n";
Also, as use
statement arguments are always parsed in the list context, sometimes you could be surprised with argument being executed in list context, instead of scalar context.
use Acme::constant TIMESTAMP => localtime; # WRONG!
Usually, when this happens, it's possible to use scalar
operator in order to force interpretation of code in scalar context.
use Acme::constant TIMESTAMP => scalar localtime;
Constants return lists, not arrays (you don't use @
syntax, do you?), so in order to get single element, you will need to put a constant in parenthesis.
use Acme::constant NUMBERS => 1..6;
print join(" ", (NUMBERS)[2..4]), "\n";
Assignments
The assignments are done using standard =
operator.
use Acme::constant SOMETHING => 1;
SOMETHING = 2;
print "Something is ", SOMETHING, ".\n";
use Acme::constant ARRAY => 1, 2, 3;
my $four = 7;
($four, ARRAY) = (4, 5, 6);
print "Something is ", join(", ", ARRAY), ", and four is $four.\n";
There are also catches about assignments. Perl normally runs the part after =
operator in scalar context, unless leftside argument is a list or array. As inconstant constant is neither a list or array, the argument on right side is ran in scalar context. For example, following code will only save 2, as comma operator is ran in scalar context.
use Acme::constant SOMETHING => 0;
SOMETHING = (1, 2); # WRONG!
print "Something is ", join(", ", SOMETHING), ".\n";
In order to force list interpretation, you need to put constant in the parenthesis.
use Acme::constant SOMETHING => 0;
(SOMETHING) = (1, 2);
print "Something is ", join(", ", SOMETHING), ".\n";
Similarly, you cannot modify list constant in scalar context, as Perl expects you put a list, not a single value.
use Acme::constant SOMETHING => (1, 2);
SOMETHING = 3; # WRONG!
print "Something is ", SOMETHING, ".\n";
To fix that, you need to put constant in parenthesis. This is only needed when constant has different number of elements than one, so after such assignment, you can use normal assignment, without parenthesis.
use Acme::constant SOMETHING => (1, 2);
(SOMETHING) = 3;
print "Something is ", SOMETHING, ".\n";
SOMETHING = 4;
print "Something is now ", SOMETHING, ".\n";
Also, the localization of Acme constants is broken, and while it will change the value, it won't change value back after leaving the block. This is related to that you cannot localize lexicals and references in Perl 5.
use Acme::constant PI => 4 * atan2 1, 1;
{
local PI = 3;
print "PI = ", PI, "\n";
}
print "PI = ", PI, "\n";
CAVEATS
Other than caveats mentioned here, general caveats about constants also exist. Unlike standard constants module, constants with names like STDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG
can be used outside main::
package, because of different method of generating constants.
The constants can be problematic to use in context that automatically stringifies the barewords. For example, the following code is wrong.
use Acme::constant KEY => "acme";
my %hash;
$hash{KEY} = 42; # Works like $hash{"KEY"} = 42;
Instead, you should use following code.
use Acme::constant KEY => "acme";
my %hash;
$hash{(KEY)} = 42;
SEE ALSO
constant - Builtin constant module.
Readonly - Constant scalars, arrays, and hashes.
BUGS
Please use GitHub to report bugs.
SOURCE
The source code for Acme::constant is available can be found https://github.com/GlitchMr/Acme-constant/.
COPYRIGHT
Copyright 2013 by Konrad Borowski <glitchmr@myopera.com>.