szabgab has asked for the wisdom of the Perl Monks concerning the following question:

Looking at the sample hooks scripts included in the Subversion distributions I see this construct:
# Turn on warnings the best way depending on the Perl version. BEGIN { if ( $] >= 5.006_000) { require warnings; import warnings; } else { $^W = 1; } }
I wonder what is the merrit in this code.

If I understand this correctly the author thinks it is important to turn on warnings for the script but not necessary for modules it uses. Hence at least for perl >= 5.6 they go for the lexically scoped warnings.

The interesting thing is that they don't really use any modules in these scripts.

Before responding see also earlier discussions on $^W vs use warnings:

Update: Here is a link to the hook scripts directory.

Replies are listed 'Best First'.
Re: $^W or require warnings and import warnings;
by davido (Cardinal) on Jun 15, 2005 at 17:55 UTC

    The code is actually sort of a failed attempt.

    The author seems to realize that the use directive occurs at compiletime, and is not easily conditionalized. So he uses the runtime-executed 'require' method of invoking a module conditionally. However, he does it within a lexical block (  if(....){ lexical block } ). The warnings pragma is lexically scoped to the block in which it is invoked, so he is only turning warnings on for a brief instant, which will not have any effect outside the if conditional block. Even if it did extend past the if(){...} block, it would be limited by the lexical scope of the BEGIN{...} block.

    You can observe this fact by modifying the code as follows:

    BEGIN{ if( $] >= 5.006_000 ) { require warnings; import warnings; print "Warnings on: $hi\n"; } else { $^W = 1; } } print "Warnings off: $hi\n";

    With this code, the output will be something to the effect of:

    Warnings on: Use of uninitialized value in mytest.pl, line xxx.... Warnings off:

    In other words, the second use of uninitialized value is in a lexical scope not covered by warnings, and thus the use of uninitialized value is not reported the second time.


    Dave

      have you actually tried your code? because I got...
      Use of uninitialized value in concatenation (.) or string at - line 10 +.
      It works because the import warnings sentence inside the BEGIN block changes the value of ${^WARNING_BITS} at compile time.

        I get the following results...

        C:\Perl\bwb>perl -v This is perl, v5.8.6 built for MSWin32-x86-multi-thread (with 3 registered patches, see perl -V for more detail) ... C:\Perl\bwb>perl 466922.pl Warnings on: Use of uninitialized value in concatenation (.) or string at 2.pl line + 10. Warnings off:

        /renz.
        "Call on God, but row away from the rocks."
        --Hunter S. Thompson.

      Good call, this definitely doesn't work the way the author intended. I wondered the same thing initially and tried something eerily similar to your code, but it seemed to warn me on both print statements. When I read your post I was definitely surprised for a few seconds, until I looked at the top of my script and found this:
      #!/usr/bin/perl -w
      So, removing the -w gave me the output you describe.

      I use perl -w in most of my scripts, so it's in my VIM template for Perl scripts. Further proof that it's important to remember your coding habits, lest they sneak up on you when you least expect it. :)

Re: $^W or require warnings and import warnings;
by bluto (Curate) on Jun 15, 2005 at 17:40 UTC
    If I understand this correctly the author thinks it is important to turn on warnings for the script but not necessary for modules it uses. Hence at least for perl >= 5.6 they go for the lexically scoped warnings.

    I tend to look at this as the author saying: I must have warnings on in my code, I'll try not to turn it on in the modules I use so they don't break in strange ways, but in perl's before 5.6 I have no choice.

    I guess they're trying to make their code as compatible as possible with perl's before 5.6 and strangely written modules, but it does seem rather cargo-cultish. On a side note: perl 5.6 has been out a long time, so I don't really see the point. Why would someone run something new like Subversion, and not bother to upgrade their ancient Perl? Upgrading parts of your system while other parts are left to rot in legacy mode just seems like trouble.

      I guess they're trying to make their code as compatible as possible with perl's before 5.6 and strangely written modules, but it does seem rather cargo-cultish. On a side note: perl 5.6 has been out a long time, so I don't really see the point. Why would someone run something new like Subversion, and not bother to upgrade their ancient Perl? Upgrading parts of your system while other parts are left to rot in legacy mode just seems like trouble.


      I think it might be jumping the gun to call that "cargo cult". There are probably lots of corporations out there who don't make upgrading perl a priority. I don't see why (if you had the time) you wouldn't include such a line.
        The problem I have with blindly including something like this is that if you expect a script to work on an ancient version of perl you need to go through hoops to avoid using newer constructs/modules, and more importantly, you really should test your script on those old versions. It's nice to be compatible, but if your script breaks on an ancient version of perl that you "support" you are not doing the poor user any favors. It's actually nicer in the long run to just say "we require 5.6 or newer" and let them install a separate copy of perl if they need to.

        Please note that I'm not saying they are doing this in this particular case, perhaps they have actually tested this on older perls. It just that it seems that way to me at first glance from the posted snippet (which may be assuming too much)...

      Why would someone run something new like Subversion, and not bother to upgrade their ancient Perl? Upgrading parts of your system while other parts are left to rot in legacy mode just seems like trouble.

      Thus spake someone who hasn't had to maintain systems for the long term. :-)

      Many times it is necessary that particular versions of perl, modules, libraries, etc. are all required just to make the mission-critical application work. "Upgrading" is often counter productive and costly (due to time lost chasing down weird interactions and fixing them among other things).

      Switching from CVS to SVN (for instance) is something that is likely to only affect the development team while switching from perl 5.005_04 to 5.8.6 may affect everybody.

        I understand about having to keep a legacy perl around to support older apps, etc, and I don't have a problem with that. It just seems like a no-brainer to also have an additional up-to-date perl (i.e. a separate install) if you plan on using up-to-date scripts. Chances are very good that these new scripts weren't actually designed or tested on your legacy perl (i.e. you'll need to test/examine them). Having a separate perl seems a lot easier to me than examining every new script you put on the machine to make sure it's going to work with your legacy perl.