Stas Bekman <[EMAIL PROTECTED]> writes: > - move the perl4 lib solution to the perl_reference.pod
Will do when I get round to that bit. I still think a mention of it is needed in porting.pod to warn people away from it. If you disagree simply delete the offending paragraph. > - suggest turning a lexical variable declared with my() into a global > variable declared with our() to avoid the closure, with the following > "but"s: > > o if with my() it wasn't crucial to initialize the variables > (since my() initialized them to 'undef'), now all variables declared with > our() must be explicitly initialized. > [Brian: notice that I prefer *not* to suggest using local() to init > vars, and rather have users do that explicitly, which is a good > practice] Well I disagree with you about it being good a practice. I personally consider it good practice to work in a way that minimises the number of things you have to do explicitly (with the exception of declarations). I can't see why you think relying on the fact that local() will initialize variables to undef is any worse than relying on the fact that my() will. But this is your document so I shall go along with your preferences. I've tried to keep it brief by moving some of the points (in particular 'use vars') into comments inside the code examples where they can be expressed more concisely. --- porting.pod.orig Fri Oct 10 18:58:48 2003 +++ porting.pod Fri Oct 10 18:42:27 2003 @@ -88,7 +88,7 @@ print "Content-type: text/plain\r\n\r\n"; - my $counter = 0; + my $counter = 0; # Explicit initialization technically redundant for (1..5) { increment_counter(); @@ -195,8 +195,8 @@ print "Content-type: text/plain\r\n\r\n"; - my $counter = 0; - + my $counter = 0; # Explicit initialization technically redundant + for (1..5) { increment_counter(); } @@ -228,51 +228,66 @@ It's important to understand that the I<inner subroutine> effect happens only with code that C<Apache::Registry> wraps with a -declaration of the C<handler> subroutine. If you put your code into a -library or module, which the main script require()'s or use()'s, this -effect doesn't occur. - -For example if we move the code from the script into the subroutine -I<run>, place the subroutines into the I<mylib.pl> file, save it in -the same directory as the script itself and require() it, there will -be no problem at all. (Don't forget the C<1;> at the end of the -library or the require() might fail.) - - mylib.pl: - --------- - my $counter; - sub run{ - print "Content-type: text/plain\r\n\r\n"; - $counter = 0; - for (1..5) { - increment_counter(); - } +declaration of the C<handler> subroutine. If you put all your code +into modules, which the main script C<use()>s, this effect doesn't +occur. + +Do not use Perl4-style libraries. Subroutines in such libraries will +only be available to the first script in any given interpreter thread +to C<require()> a library of any given name. This can lead to +confusing sporadic failures. + +The easiest and the fastest way to solve the nested subroutines +problem is to switch from lexical scope to package scope for all +variables for which you get the warning. The C<handler> subroutines +are never called re-entrantly and each resides in a package to itself. +Most of the usual disadvantates of package scoped variables are, +therefore, not a concern. Note, however, that whereas explicit +initialization is often redundant for lexical variables it is usually +not redundant for these package variables as they are reused in +subsequent executions of the handler. + + counter.pl: + ---------- + #!/usr/bin/perl -w + use strict; + + print "Content-type: text/plain\r\n\r\n"; + + # In Perl <5.6 our() did not exist, so: + # use vars qw($counter); + our $counter = 0; # Explicit initialization now necessary + + for (1..5) { + increment_counter(); } + sub increment_counter{ $counter++; print "Counter is equal to $counter !\r\n"; } - 1; - - counter.pl: - ---------- - use strict; - require "./mylib.pl"; - run(); -This solution provides the easiest and the fastest way to solve the -nested subroutines problem, since all you have to do is to move the -code into a separate file, by first wrapping the initial code into -some function that you later will call from the script and keeping the -lexically scoped variables that could cause the problem out of this -function. - -But as a general rule of thumb, unless the script is very short, I -tend to write all the code in external libraries, and to have only a -few lines in the main script. Generally the main script simply calls -the main function of my library. Usually I call it C<init()> or -C<run()>. I don't worry about nested subroutine effects anymore -(unless I create them myself :). +If the shared variable contains a reference it my hold onto lots of +unecessary memory (or worse) if the reference is left to hang about +until the next call to the same handler. For such variables you +should use C<local> so that the value is removed when the C<handler> +subroutine exits. + + my $query = CGI->new; + +becomes: + + local our $query = CGI->new; + +As side effect, if you use C<local> you no longer need to add explicit +initialization of variables to undef. + +All this is very interesting but as a general rule of thumb, unless +the script is very short, I tend to write all the code in external +libraries, and to have only a few lines in the main script. Generally +the main script simply calls the main function of my library. Usually +I call it C<init()> or C<run()>. I don't worry about nested +subroutine effects anymore (unless I create them myself :). The section 'L<Remedies for Inner Subroutines|general::perl_reference::perl_reference/Remedies_for_Inner_Subroutines>' discusses -- \\ ( ) . _\\__[oo .__/ \\ /\@ . l___\\ # ll l\\ ###LL LL\\