stas        2003/11/14 22:12:21

  Modified:    src/docs/1.0/guide porting.pod Changes.pod
               src/docs/general/perl_reference perl_reference.pod
               src/docs/general Changes.pod
  Log:
  modernize coding techniques sections in porting.pod and perl_reference
  Submitted by: Brian McCauley <[EMAIL PROTECTED]>
  
  Revision  Changes    Path
  1.20      +56 -42    modperl-docs/src/docs/1.0/guide/porting.pod
  
  Index: porting.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/1.0/guide/porting.pod,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -u -r1.19 -r1.20
  --- porting.pod       15 Jul 2003 11:06:02 -0000      1.19
  +++ porting.pod       15 Nov 2003 06:12:21 -0000      1.20
  @@ -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,65 @@
   
   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 every lexically scoped variable foe which you get
  +the warning for to a package variable. 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 not always necessary for lexical variables it is
  +usually necessary for these package variables as they persist in
  +subsequent executions of the handler and unlike lexical variables,
  +don't get automatically destroyed at the end of each 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 variable contains a reference it may 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;
  +
  +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 
  
  
  
  1.37      +5 -0      modperl-docs/src/docs/1.0/guide/Changes.pod
  
  Index: Changes.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/1.0/guide/Changes.pod,v
  retrieving revision 1.36
  retrieving revision 1.37
  diff -u -u -r1.36 -r1.37
  --- Changes.pod       20 Dec 2002 06:13:29 -0000      1.36
  +++ Changes.pod       15 Nov 2003 06:12:21 -0000      1.37
  @@ -11,6 +11,11 @@
   
   =head1 Ongoing
   
  +* porting.pod
  +
  + o revamp the "Exposing Apache::Registry secrets" section to use
  +   modern techniques [Brian McCauley <nobull /at/ cpan.org>]
  +
   * coding.pod:
   
    o clarify the issue with END blocks in packages loaded from the
  
  
  
  1.3       +126 -29   
modperl-docs/src/docs/general/perl_reference/perl_reference.pod
  
  Index: perl_reference.pod
  ===================================================================
  RCS file: 
/home/cvs/modperl-docs/src/docs/general/perl_reference/perl_reference.pod,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- perl_reference.pod        9 Feb 2003 02:05:20 -0000       1.2
  +++ perl_reference.pod        15 Nov 2003 06:12:21 -0000      1.3
  @@ -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 suggested in the past, and we
  +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,27 @@
     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 is not quite
  +what happens.  On each execution of run() a new C<$counter> variable
  +is initialized to zero but increment_counter() remains bound to the
  +C<$counter> variable from the first call to run().
  +
  +The simplest of the work-rounds is to use package-scoped variables.
  +These can be 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 will probably need to add explicit initialisation
  +for variables that lacked it.
   
     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 +954,7 @@
     
     sub run {
     
  -    $counter = 0;
  +    our $counter = 0;
     
       increment_counter();
       increment_counter();
  @@ -977,11 +985,37 @@
   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 can put C<local> in
  +front of the C<our> declaration of 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, if you recall that thing I said about adding 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.  If
  +the original CGI script relied upon process termination to clean up
  +after it then it will leak memory as a registry script.
  +
  +A varient of the package variable approach is not to declare your
  +variables, but instead to use explicit package qualifiers.  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.
  +Another downside is that you become dependant on the "used only once"
  +warning to detect typos in variable names.  The explicit package name
  +approach is not really suitable for registry scripts because it
  +pollutes the C<main::> namespace rather than staying properly within
  +the namespace that has been allocated.  Finally, note that the
  +overhead of loading the C<vars> module only has to be paid once per
  +Perl interpreter.
   
     multirun2.pl
  -  -----------
  +  ------------
     #!/usr/bin/perl -w
     
     use strict;
  @@ -1019,10 +1053,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 +1091,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 +1128,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 +1157,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 throughout
  +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 oncluded 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,8 +1188,54 @@
   
     multirun6-lib.pl
     ----------------
  -  use strict ;
  +  use strict;
  +  use warnings;
  +  
  +  my $counter;
  +
  +  sub run {
  +    $counter = 0;
  +
  +    increment_counter();
  +    increment_counter();
  +  }
  +  
  +  sub increment_counter{
  +    $counter++;
  +    print "Counter is equal to $counter !\n";
  +  }
  +  
  +  1 ;
  +
  +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 global uniqueness requirement still applies
  +to the module name, but at least this is a problem Perl programmers
  +should already be familiar with when creating modules.
  +
  +  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 {
  @@ -1156,7 +1252,8 @@
     
     1 ;
   
  -Now you have at least six workarounds to choose from.
  +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.
   
  
  
  
  1.10      +3 -0      modperl-docs/src/docs/general/Changes.pod
  
  Index: Changes.pod
  ===================================================================
  RCS file: /home/cvs/modperl-docs/src/docs/general/Changes.pod,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -u -r1.9 -r1.10
  --- Changes.pod       31 Jul 2002 14:38:31 -0000      1.9
  +++ Changes.pod       15 Nov 2003 06:12:21 -0000      1.10
  @@ -29,6 +29,9 @@
   
   * perf_reference:
   
  +  o revamp the "Remedies for Inner Subroutines" section to use modern
  +    techniques [Brian McCauley <nobull /at/ cpan.org>]
  +
     o added a section on overriding functions to trace their failure.
   
     o inlined Mike Guy's news article about closures
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to