Re: PATCH porting.pod First Mystery

2003-09-05 Thread Brian McCauley
Stas Bekman [EMAIL PROTECTED] writes:

 local is perl4-ism, nowadays it's used only for localizing special
 perl variables, like $|.

Using package variables and local() in to do the job of block-scoped
lexicals is a Perl4-ism.

On the other hand, when using global variables (in which I include
Perl's package variables and Perl's file-scoped lexicals) something
with the semantics of local() is useful.  It is, therefore, annoying
that local cannot be used on lexical variables and even LW has said
that this restriction is artifical and wrong.

I agree that as a programming technique global variables are vulgar.
However the First Mystery is all about porting CGI scripts that are
already using global variables (implemented using file-scoped
lexicals).  It is the use of global variables in the first place that
is vulgar, using local() does not make the code any more vulgar.
 
  Secongly it's a smaller change.
 
 Agreed, but it's not the proper change, your change can break
 code.

Only in really obscure circumstances.  Of course, if at the same time,
you make an unrelated change that breaks the code I can see how you'd
be tempted to blame me. :-)

 Assuming that we had:
 
 use warnings;
 my $counter = 0;
 print hit $counter times;
 
 Your change:
 
 use warnings;
 local our $counter;
 print hit $counter times;

No, that's not my change, I said to change my to local our.  I
didn't say to remove initialization.

  Anyhow, local() does something quite different.  It undefines it upon
  exit of the current scope.

 On the exit of the scope local() restores the previous value if any,
 and if none was assigned in first place (which implies undef) it's
 reset to undef. 

Yes, I know that.

 I don't think it has anything to do with finalization, it just looks
 like it does.

Bluebells are not blue, they are actually pink and just look like
they are blue :-)

I use the term 'finalization' to (amongst other things) refer to
declaring an action that is to take place when a given scope is
removed from the execution stack.  This is what 'local' does.
The word, however, is not important as I don't propose to use it in
the guide.

 However I'm not against your 'local our' solution, I'm just saying
 that it's less obvious than an explicit initialization, even though it
 requires more modification. Not-very advanced users will just get
 confused by this solution. Normally variables need to be initialized
 before they are used, so they will have to init them in any case and
 undef is not what they want.

The porting guide assumes we start with a working CGI script.  If a
variable needs to be initialized to a value other than undef then a
working script must already do so.

 For example we can provide an explicit initialization example

The example in my modified porting.pod already shows explicit
initialization:

  local our $counter = 0;

 after that suggest that you can say 'local our $foo' to globalize and
 localize it at the same time if you prefer to init those to undef via
 local(). Sounds like a good compromise to me.

That fails to mention the real reason for using local.

  [ about use vars ]
 The guide is written to reduce the number of questions, not raise
 their number. Solution: mention both (our and use vars)

How about we leave the example as I have it now and say:

   In this simple example, 'local' is redundant because $counter is
   explicitly initialized and never holds a reference.  For variables
   that hold references (especially to objects interfacing to entities
   outside Perl) 'local' ensures timely destruction.  For variables
   lacking explicit initialization 'local' also initializes them to
   undefined.

   The 'our' function appeared in 5.6, for backward compatability:

  use vars qw( $counter );
  $counter = 0;

We could also go on to talk about the option of explicitly
initializing variables with undef() to save the minute overhead of
using local() but I think that's unwarranted in porting.pod.  Perhaps
it should be covered in perl_reference.pod.

  [ file handle example ]
 
 I didn't suggest that particular use

I realise that the simple file handle example was a poor choice to
illustrate my point.  Here's a better example that could form the
basis of a more verbose explation in perl_reference.pod.

Suppose you have:

 my $thing = Thing-new;

Now suppose that Thing objects involve lots of resources (shared
memory segments, temporary files, large Perl data structures,
network connections various database/NNTP/SNPP/whatever servers
and so on) and/or suppose that Thing objects perform some sort of
output buffering and then flush it in Thing::DESTROY.

If I change that to:

 our $thing = Thing-new;

Then all of these resources are held until the script is next run
or until the interpreter thread is killed.

If I change it to:

 local our $thing = Thing-new;

It does the right thing.

You might think you could simply undef($thing) 

Re: PATCH porting.pod First Mystery

2003-09-03 Thread Brian McCauley
Stas Bekman [EMAIL PROTECTED] writes:

 Brian McCauley wrote:
 [...]
 Nice, but:
 
   +The easiest and the fastest way to solve the nested subroutines
   +problem is to change Cmy to Clocal Cour for all variables for
   +which you get the warning.  The Chandler subroutines are never
 ...
 [...]
   +  local our $counter = 0;
 
 local our? That should be either local or our, but not both.
  No.
 
 Do I miss something?
  Yes.  (I tried to explain this in Paris but I was in danger of
  causing
  you to miss lunch completely).
  local() and our() do two quite separate and complementary things.
  our() (in effect) declares a lexically scoped alias for a package
  variable.
  local() restores the old value of a package variable (usually undef)
  at the end of the current lexical scope.
 
 In effect you use local() to undef the variable, instead of explicitly
 initializing it. Why not doing this explictly?

Firstly it's conceptually neater to use local.  I want to think of the
variable as local rather than as a global variable that needs to be
explicitly reset.

Secongly it's a smaller change.

Thirdly you can never be sure the undef would be reached. (I realise
after reading the rest of your mail that that statement will not make
any sense to you because you've misunderstood what local does and
hense where the undef would need to go).

 so instead of replacing:
 
 my $counter;
 
 with:
 
 local our $counter;
 
 it's probably better to say:
 
 our $counter = 0;

Surely you meant:

 undef our $counter;

Or 

  our $counter = undef.

In this case $counter is treated a a number so it's OK to use 0 but
the aim of the game is to come up with a drop-in replacement for all
lexically scoped variables that suffer will not remain shared.

Anyhow, local() does something quite different.  It undefines it upon
exit of the current scope.  Obviously _most_ of the time it matters
little if the variable is undef on exiting the scope or re-entering it
next time.  But why bother storing up troubles.  Better to do the
right thing from the outset.

 or if you insist on using both:
 
 our $counter;
 local $counter; # undef $counter

Why split them?  Doesn't aid readability.  Is a pain if the original
my() was inside an expression.

The comment is confusing.  It implies that local performs
initialization.  It doesn't.  It performs finalization.

The comment should read:

 local $counter; # Automatically undef $counter when script terminates

 later on I show why this is better for user's understanding.

Really?

  The two combined therefore give a package variable two of the most
  useful properties of a lexical one.  Of course a real lexical variable
  doesn't really become undefined when it does out of scope - it really
  becomes anonymous, and iff there are no remaining (unweakened)
  references it then gets GCed.  But for file-scoped lexicals in the
  main script file the difference is usually not that important.  Both
  effectively get killed at the point where global destruction would
  have taken place.
 
 The rest looks good, but that's not the simplest solution as you have
 to modify the variables.
  Is there a simpler one?  For a typical script with say half a dozen
  variables the would not remain shared the local our solution
  requires a dozen keystokes on each of half a dozen lines.
 
 Don't forget that our() is not available before perl 5.6. So we can't
 quite eliminate the previous solution unless you suggest to go with a
 back-compatible version:
 
 use vars qw($counter);
 local $counter;

I thought enough time has gone by that 5.6 can be considered the norm
and the tiny fraction of people doing on-going work on legacy pre-5.6
system should be expected to be familar with the work-rounds required.
On that basis I concuded that the work-rounds needed to get arround
the lack of our() in 5.5 are outside the scope of the the porting
document and belonged in the perl_reference.  In my (as yet
incomplete) revision of the perl_reference document I include mention
of 'use vars'.  If you think this should be in porting I'm not going
to argue.

 and of course the proper solution is:
 
 use vars qw($counter);
 $counter = 0; # or undef

No, the proper solution is:

  local our $counter;
 
IMNSHO use vars is not the proper solution, it is a backward
compatability work-round for people still using old versions of Perl
that prevent them using the proper solution.

Initialization is not the proper solution.  In some cases, like the
case of the simple counter you can get away with using initialization.
But the proper solution is finalization (using local).  To see why
consider a CGI script that contains, at file scope:

  open my $file, '', $outfile or die $outfile: $!;

What happens if you change that to:

  use vars qw($file);
  $file = undef;
  open $file, '', $outfile or die $!;

Well firstly it looks way ugly :-) !  Much more importantly it doesn't
close the file when the script terminates.

  open local our $file, '', $outfile

Re: PATCH porting.pod First Mystery

2003-09-01 Thread Brian McCauley
Stas Bekman [EMAIL PROTECTED] writes:

 [EMAIL PROTECTED] wrote:
  In private mail Stas Bekman [EMAIL PROTECTED] writes:
 
 oops, that should be the modperl list... at modperl-docs we discuss
 mostly site/docs techical issues and there are very few people on this
 list to get enough exposure for this kind of feedback request.
  Patch for The First Mystery section of the mod_perl porting guide
  as
  per my conversation with Stas at YAPC::Europe::2003.
  Takes out the suggestion of creating a Perl4-style library in the
  same
  directory as a means to port CGI scripts.
  Replaces it with something simpler and more reliable.
 
 Nice, but:
 
   +The easiest and the fastest way to solve the nested subroutines
   +problem is to change Cmy to Clocal Cour for all variables for
   +which you get the warning.  The Chandler subroutines are never
 ...
 [...]
   +  local our $counter = 0;
 
 local our? That should be either local or our, but not both.

No.

 Do I miss something?

Yes.  (I tried to explain this in Paris but I was in danger of causing
you to miss lunch completely).

local() and our() do two quite separate and complementary things.

our() (in effect) declares a lexically scoped alias for a package
variable.

local() restores the old value of a package variable (usually undef)
at the end of the current lexical scope.

The two combined therefore give a package variable two of the most
useful properties of a lexical one.  Of course a real lexical variable
doesn't really become undefined when it does out of scope - it really
becomes anonymous, and iff there are no remaining (unweakened)
references it then gets GCed.  But for file-scoped lexicals in the
main script file the difference is usually not that important.  Both
effectively get killed at the point where global destruction would
have taken place.
 
 The rest looks good, but that's not the simplest solution as you have
 to modify the variables.

Is there a simpler one?  For a typical script with say half a dozen
variables the would not remain shared the local our solution
requires a dozen keystokes on each of half a dozen lines.

 Granted, the original simplest solution has its troubles.

The original simplest solution involved finding (and subsequently
maintaining) a globally unique filename then splitting the program in
to two parts.  Thereafer you have to maintain two files even on CGI
servers.  I would contend that this simple solution is not simple.
If you are going to all that troble you may as well to the extra
804.65m and produce a proper mod_perl handler and a small wrapper to
make it work also in a CGI environment.  Also, as of mod_perl2, the
simple solution is not even, as it stands, a solution as it relied
on the script being in the CWD.


-- 
Reporting bugs: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html