Stas Bekman <[EMAIL PROTECTED]> writes:
> Brian McCauley wrote:
>
> > I think porting.pod is done.
>
> Indeed.
>
> > Now I have to attack perl_reference.pod,
> > and I assume from what you said before you don't want to release the
> > one without the other.
>
> Yes. Let's commit them together.
Here's a _very_ rough first cut at perl_reference.pod. I haven't even
proof-read it yet so it's probably got spelling a and grammar errors
but I just want to be sure I'm going in the right direction.
--- perl_reference.pod.orig Thu Aug 14 18:11:11 2003
+++ perl_reference.pod Fri Oct 31 19:46:56 2003
@@ -863,16 +863,17 @@
problem, Perl will always alert you.
Given that you have a script that has this problem, what are the ways
-to solve it? There are many of them and we will discuss some of them
-here.
+to solve it? There have been many of them suggested in the past and we
+will discuss some of them here.
We will use the following code to show the different solutions.
multirun.pl
-----------
- #!/usr/bin/perl -w
+ #!/usr/bin/perl
use strict;
+ use warnings;
for (1..3){
print "run: [time $_]\n";
@@ -925,20 +926,26 @@
Counter is equal to 5 !
Counter is equal to 6 !
-Obviously, the C<$counter> variable is not reinitialized on each
-execution of run(). It retains its value from the previous execution,
-and sub increment_counter() increments that.
-
-One of the workarounds is to use globally declared variables, with the
-C<vars> pragma.
+Apparently, the C<$counter> variable is not reinitialized on each
+execution of run(), it retains its value from the previous execution,
+and increment_counter() increments that. Actually that's not quite
+what happens. On each execution of run() a new C<$counter> variable
+is initialized to zero but increment_counter is remains bound to the
+C<$counter> variable from the first call to run().
+
+The simplest of the workarounds is to use package-scoped variables,
+declared using C<our> or, on older versions of Perl, the C<vars>
+pragma. Note that whereas using C<my> declaration also implicitly
+initializes variables to undefined the C<our> declaration does not,
+and so you may need to add explicit initialisation.
multirun1.pl
- -----------
- #!/usr/bin/perl -w
+ ------------
+ #!/usr/bin/perl
use strict;
- use vars qw($counter);
-
+ use warnings;
+
for (1..3){
print "run: [time $_]\n";
run();
@@ -946,7 +953,7 @@
sub run {
- $counter = 0;
+ our $counter = 0;
increment_counter();
increment_counter();
@@ -977,11 +984,34 @@
problem, since there is no C<my()> (lexically defined) variable used
in the nested subroutine.
-Another approach is to use fully qualified variables. This is better,
-since less memory will be used, but it adds a typing overhead:
+In the above example we know C<$counter> is just a simple small
+scalar. In the general case variables could reference external
+resource handles or large data structures. In that situation the fact
+that the variable would not be released immediately when run()
+completes could be a problem. To avoid this you should put C<local>
+in front of all you C<our> declarations for all variables other than
+simple scalars. This has the effect of restoring the variable to its
+previous value (usually undefined) upon exit from the current scope.
+As a side-effect C<local> also initializes the variables to C<undef>.
+So, you recall that thing I said about needing to remeber to add
+explicit initialization when you replace C<my> by C<our>, well you can
+forget it again if you replace C<my> with C<local our>.
+
+Be warned that C<local> will not release circular data structures and
+if the original CGI script relied on process termination to clean up
+after it then it will leak memory as a registry script.
+
+A varient of the package variable approach is to use explicit package
+qualified variables. This has the advantage on old versions of Perl
+that there is no need to load the C<vars> module, but it adds a
+significant typing overhead. This approach is not suitable for
+registry scripts because they would all be stomping on the C<main::>
+namespace rather than each staying within the namespace allocated to
+them. And, besides, the overhead of loading the C<vars> module would
+only have to be paid one per Perl interpreter.
multirun2.pl
- -----------
+ ------------
#!/usr/bin/perl -w
use strict;
@@ -993,14 +1023,14 @@
sub run {
- $main::counter = 0;
+ $::counter = 0;
increment_counter();
increment_counter();
sub increment_counter{
- $main::counter++;
- print "Counter is equal to $main::counter !\n";
+ $::counter++;
+ print "Counter is equal to $::counter !\n";
}
} # end of sub run
@@ -1019,10 +1049,11 @@
and then submit it for your script to process.
multirun3.pl
- -----------
- #!/usr/bin/perl -w
+ ------------
+ #!/usr/bin/perl
use strict;
+ use warnings;
for (1..3){
print "run: [time $_]\n";
@@ -1056,10 +1087,11 @@
variables in a calling function.
multirun4.pl
- -----------
- #!/usr/bin/perl -w
+ ------------
+ #!/usr/bin/perl
use strict;
+ use warnings;
for (1..3){
print "run: [time $_]\n";
@@ -1092,10 +1124,11 @@
a literal, e.g. I<increment_counter(5)>).
multirun5.pl
- -----------
- #!/usr/bin/perl -w
+ ------------
+ #!/usr/bin/perl
use strict;
+ use warnings;
for (1..3){
print "run: [time $_]\n";
@@ -1120,14 +1153,27 @@
Here is a solution that avoids the problem entirely by splitting the
code into two files; the first is really just a wrapper and loader,
-the second file contains the heart of the code.
+the second file contains the heart of the code. This second file must
+go into a directory in your C<@INC>. Some people like to put the
+library in the same directory as the script but this assumes that the
+current working directory will be equal to the directory where the
+script is located and also that C<@INC> will contain C<'.'>, neither
+of which are assumptions you should expect to hold in all cases.
+
+Note that the name chosen for the library must be unique thoughout the
+entire server and indeed every server on which you many ever install
+the script. This solution is probably more trouble than it is worth -
+it is only included here because it was mentioned in previous versions
+of this guide.
multirun6.pl
- -----------
- #!/usr/bin/perl -w
+ ------------
+ #!/usr/bin/perl
use strict;
- require 'multirun6-lib.pl' ;
+ use warnings;
+
+ require 'multirun6-lib.pl';
for (1..3){
print "run: [time $_]\n";
@@ -1138,7 +1184,8 @@
multirun6-lib.pl
----------------
- use strict ;
+ use strict;
+ use warnings;
my $counter;
@@ -1156,7 +1203,53 @@
1 ;
-Now you have at least six workarounds to choose from.
+An alternative verion of the above, that mitigates some of the
+disadvantages, is to use a Perl5-style Exporter module rather than a
+Perl4-style library. The requirement of global uniqueness of the
+module name still applies but at least this is a problem we're already
+familiar with.
+
+ multirun7.pl
+ ------------
+ #!/usr/bin/perl
+
+ use strict;
+ use warnings;
+ use My::Multirun7;
+
+ for (1..3){
+ print "run: [time $_]\n";
+ run();
+ }
+
+Separate file:
+
+ My/Multirun7.pm
+ ----------------
+ package My::Multirun7;
+ use strict;
+ use warnings;
+ use base qw( Exporter );
+ our @EXPORT = qw( run );
+
+ my $counter;
+
+ sub run {
+ $counter = 0;
+
+ increment_counter();
+ increment_counter();
+ }
+
+ sub increment_counter{
+ $counter++;
+ print "Counter is equal to $counter !\n";
+ }
+
+ 1 ;
+
+Now you have at least five workarounds to choose from (not counting
+numbers 2 and 6).
For more information please refer to perlref and perlsub manpages.