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 C<my> to C<local> C<our> for all variables for > >> > +which you get the warning. The C<handler> 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 or die $!; This is a much smaller change to the original script. It looks much cleaner. And most importantly it actually works. > >>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. > > Remember, we are talking about mp1 guide patching. Not everything that > applies to mp1 applies to mp2. OK, please forget I ever mentioned mp2. > [...] I hope that the problem with CWD will be resolved [...] The problem with CWD is not that simple. The trouble with advising people to create Perl4-style library in the same diectory as the script is that it is not intuatively obvious that the leafname of that library needs to unique for each ported CGI script. That's not just unique within the directory. It's not even just unique accross the whole server. It needs to be unique across all servers on which the script may ever be installed! This namespace problem is not new to Perl programmers. It is, indeed, exactly the same problem as the naming of modules. So why not spend the extra minuite or so of effort to make a proper Perl5-style library (i.e. a module using Exporter) instead and reduce two problems to one. Furthermore consider an inexperienced Perl programmer who rips the guts out of a GCI script into a Perl4-style library. There's a strong chance that he'll then think "hey, I've got this library now, let's use it in another CGI script too". This, of course, will produce a script that works under CGI but fails sporadically under mod_perl. I'm not inventing these problems. I've dealt with the fallout from the current porting guide in comp.lang.perl.* a few times. Far better not to expose people to the Perl4-style library solution at all (except perhaps to warn them against it). In the post-patch version of 'porting' I give them a simple choice: First choice - move the guts of your CGI into modules. (This is in fact 95% of the way to porting your script to a native mod_perl hander). Second choice - leave the script 99.9% untouched but use localised package variables for any variables that are, in the design of the script, already global. > If you think that using globals + their initialization is a better > solution, No, initialization is not a good solution. Finalisation is what is wanted. The use of term "global" to refer to Perl's package variables is misleading. >From the point of view of program design file-scoped lexicals are global variables. By suggesting the use of package variables I'm not suggesting that anyone start using the programming technique of global variables in place of something else. What we are dealing with here is the situation where one has a CGI script that already has a design that uses global variables. These global variables happen to be implemented as file-scoped lexicals. To port this script to run as a mod_perl registry script the _simplest_ change is just to choose to implement these variables as localised package variables instead. > [...] we can replace the lib.pl solution with it, Good. > but should add it to the perl reference section. I can't work out what "it" referrs to above. Both solutions should appear in the perl reference section. The lib.pl solution should not appear in porting, and even if it did then it defintely should not be described by saying: "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,..." because that's simply untrue (on two counts). "Move the code into a separate file" is not "all you have to do". Before you can do that you have to choose a globally unique filename for your file. And remember I mean _globally_ unique - it must not clash with one used in any other registry script on any server where the script will ever be installed. Even if "move the code into a separate file" _was_ all you had to do that would still be a couple of orders of magnitude more effort than the "local our" solution thus it would still not be "the easiest and the fastest way". -- Reporting bugs: http://perl.apache.org/bugs/ Mail list info: http://perl.apache.org/maillist/modperl.html