I'm looking for advice on Perl best practices. I wrote a script which had a complicated regular expression:
my $regex = qr/complicated/;
# ...
sub foo {
# ...
if (/$regex/)
# ...
}
where foo
is a function which is called often, and $regex
is not used outside that function. What is the best way to handle situations like this? I only want it to be interpreted once, since it's long and complicated. But it seems a bit questionable to have it in global scope since it's only used in that sub. Is there a reasonable way to declare it static?
A similar issue arises with another possibly-unjustified global. It reads in the current date and time and formats it appropriately. This is also used many times, and again only in one function. But in this case it's even more important that it not be re-initialized, since I want all instances of the date-time to be the same from a given invocation of the script, even if the minutes roll over during execution.
At the moment I have something like
my ($regex, $DT);
sub driver {
$regex = qr/complicated/;
$DT = dateTime();
# ...
}
# ...
driver();
which at least slightly segregates it. But perhaps there are better ways.
Again: I'm looking for the right way to do this, in terms of following best practices and Perl idioms. Performance is nice but readability and other needs take priority if I can't have everything.
Using the Parameter Array (@_) Perl lets you pass any number of parameters to a function. The function decides which parameters to use and in what order.
Perl has three main variable types: scalars, arrays, and hashes. A scalar represents a single value: my $animal = "camel"; my $answer = 42; Scalar values can be strings, integers or floating point numbers, and Perl will automatically convert between them as required.
$$ The process number of the perl running this script. (Mnemonic: same as shells.) $? The status returned by the last pipe close, backtick (\`\`) command or system operator.
The most commonly used special variable is $_, which contains the default input and pattern-searching string. For example, in the following lines − #!/usr/bin/perl foreach ('hickory','dickory','doc') { print $_; print "\n"; }
If you're using perl 5.10+, use a state
variable.
use feature 'state';
# use 5.010; also works
sub womble {
state $foo = something_expensive();
return $foo ** 2;
}
will only call something_expensive
once.
If you need to work with older perls, then use a lexical variable in an outer scope with an extra pair of braces:
{
my $foo = something_expensive();
sub womble {
return $foo ** 2;
}
}
this keeps $foo
from leaking to anyone except for womble
.
Is there any interpolation in the pattern? If not, the pattern will only be compiled once no matter how many times the qr// is executed.
$ perl -Mre=debug -e'qr/foo/ for 1..10' 2>&1 | grep Compiling | wc -l
1
$ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l
10
Even if there is interpolation, the pattern will only be compiled if the interpolated variables have changed.
$ perl -Mre=debug -e'$x=123; qr/foo$x/ for 1..10;' 2>&1 | grep Compiling | wc -l
1
$ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l
10
Otherwise, you can use
{
my $re = qr/.../;
sub foo {
...
/$re/
...
}
}
or
use feature qw( state );
sub foo {
state $re = qr/.../;
...
/$re/
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With