Loading ...
Sorry, an error occurred while loading the content.

54310Re: PATCH porting.pod "First Mystery"

Expand Messages
  • Stas Bekman
    Sep 3, 2003
      >>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.

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

      > Secongly it's a smaller change.

      Agreed, but it's not the proper change, your change can break code. Assuming
      that we had:

      use warnings;
      my $counter = 0;
      print "hit $counter times";

      Your change:

      use warnings;
      local our $counter;
      print "hit $counter times";

      will generate a warning: Use of uninitialized value in concatenation (.) or
      string at ...

      We have to teach users to initialize globals, not localize them. See more below.

      > Thirdly you can never be sure the undef would be reached.

      And nobody wants it to be reached. The problem is at the beginning of the
      subsequent request, not at the end of the first request. See more below.

      >>so instead of replacing:
      >>my $counter;
      >>local our $counter;
      >>it's probably better to say:
      >>our $counter = 0;
      > Surely you meant:
      > undef our $counter;
      > Or
      > our $counter = undef.

      No I meant = 0, because that's what the original example does. We try to solve
      the problem with:

      my $counter = 0;


      our $counter = 0;

      does the trick. if you replace

      my $counter = 0;


      local our $counter;

      you lose the initialization. This won't work under 'use warnings', which is
      not clear from the example, but perhaps it should be fixed to do that.

      > 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.

      I beg your pardon, how did you come up to this conclusion. Point me to the
      documentation or the source code where this is done. 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. I don't think it has anything
      to do with finalization, it just looks like it does.

      Your code:

      local our $counter;

      is essentially:

      our $counter; # undef
      { local $counter; # new undef unrelated to the previous one
      $counter = 0; # you missed this, but it's unrelated
      # $counter == the very first undef here, because it was undef before local was

      And just to prove you that you aren't so correct with this finalization idea,
      run the following code:

      perl-5.8.1 -lwe 'our $x = 5; { local $x = 6 } print $x'

      it prints '5', not undef. so it's *restored* to its previous value not reset
      to undef. now this:

      perl-5.8.1 -lwe 'our $x; { local $x = 6 } print $x'

      will indeed restore $x to undef, because that's how it was before local...

      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.

      For example we can provide an explicit initialization example and 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.

      > 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.

      That's what I suggested, just wasn't clear about it. It should be moved out of
      porting.pod into perl_reference.pod.

      > 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.

      Well, what users that do happen to use perl < 5.6 should do? The guide is
      written to reduce the number of questions, not raise their number. Solution:
      mention both (our and use vars)

      > 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 :-) !

      Secondly, it doesn't work under perl < 5.6, so the point is moot if it's made
      clear ;)

      > Much more importantly it doesn't
      > close the file when the script terminates.

      I didn't suggest that particular use, however the suggestion in the guide is
      global and implies that it should work. All I can say here is that closing the
      file explicitly is a good practice, but otherwise you are right.

      > 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.

      so does:

      open our $file, '>', $outfile or die $!;

      no? and it works because you don't need to initialize $file

      > The problem with CWD is not that simple.
      > The trouble with advising people to create Perl4-style library in the


      But I have already agreed that perl4-style libs solution should be moved to
      the perl_reference.pod doc... I agree with your arguments.

      To summarize:

      - move the perl4 lib solution to the perl_reference.pod
      - suggest replacing my() with our() to avoid the closure, however this change
      requires that the variables will be initialized before used in most cases
      (example of 'open our $foo' which doesn't need to be initialized). you can
      initialize variables by an explicit assignment of the value, or using the
      'local our' trick, which will initialize the variable to under, which is
      probably not what you want.
      - for users of perl < 5.6 suggest to use 'use vars' instead of 'our'.
      - point to perl_reference.pod for other workarounds/solutions.

      Does it sound good?

      Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
      http://stason.org/ mod_perl Guide ---> http://perl.apache.org
      mailto:stas@... http://use.perl.org http://apacheweek.com
      http://modperlbook.org http://apache.org http://ticketmaster.com

      Reporting bugs: http://perl.apache.org/bugs/
      Mail list info: http://perl.apache.org/maillist/modperl.html
    • Show all 20 messages in this topic