Today I visited a website devoted to Perl, and was amazed to find (yet again) examples of perl code which made no mention of "use strict" and "use warnings", yet advocated the use of global variables (not lexically scoped with "my").

Serendipitously, a few minutes later I was working on my own Perl script, and a minor change I made generated a warning which I thought might be of value to share.  I know it's been said here before (and if you're a devout believer already, you know where I'm coming from), but I sincerely believe that the use of warnings and strict are the 2 best ways you can improve your programming!

First, here's the program (simplified to a tenth its original size):

#!/usr/bin/perl -w # # Demonstrate the importance of "use warnings" and "use strict"! # 051004 liverpole # ############## ### Strict ### ############## use strict; use warnings; ################## ### Prototypes ### ################## sub ratio_change($$$$); sub random_change($); #################### ### Main program ### #################### my $start_value = my $new_value = 100; my $start_total = my $new_total = 1000; my $ratio0 = 100 * $start_value / $start_total; my $ratio1 = $ratio0; for (my $i = 0; $i < 100000; $i++) { if (ratio_change($start_value, $start_total, $new_value, $new_tota +l)) { $ratio1 = $ratio1 = 100 * $new_value / $new_total; } $start_value = $new_value; $start_total = $new_total; $new_value = random_change($start_value); $new_total = random_change($start_total); } printf "Start percentage ... %7.4f%%\n", $ratio0; printf " End percentage ... %7.4f%%\n", $ratio1; ################### ### Subroutines ### ################### sub random_change($) { my ($value) = @_; (rand(100) > 0.005) and return $value; # No change 99.995% of the + time return $value + int(rand(3)) - 1; # Make a change of -1, 0, +or +1 } sub ratio_change($$$$) { my ($value0, $total0, $value1, $total1) = @_; my $ratio0 = $value0 / $total0; my $ratio1 = $value1 / $total1; ($ratio0 == $ratio1) and return 0; # No change in ratio my $text = "Ratio Change: $ratio0 => $ratio1\n"; print STDERR $text; return 1; }
When run, this generates pseudo-random delta changes to a ratio of values, displaying the new ratios when they are different, and at the end shows the starting and ending ratios as percentages:
Ratio Change: 0.1 => 0.101 Ratio Change: 0.101 => 0.100899100899101 Ratio Change: 0.100899100899101 => 0.101898101898102 Ratio Change: 0.101898101898102 => 0.100899100899101 Ratio Change: 0.100899100899101 => 0.0999000999000999 Ratio Change: 0.0999000999000999 => 0.0989010989010989 Ratio Change: 0.0989010989010989 => 0.0988023952095808 Start percentage ... 10.0000% End percentage ... 9.8802%
What happened next was that I decided to modify line 59 to show the percentages to only 4 decimal places, and in altering the line, didn't pay attention to the fact that it wasn't a sprintf statement.   Thus I changed:
my $text = "Ratio Change: $ratio0 => $ratio1\n";
to:
my $text = "Ratio Change: %7.4f => %7.4f\n", $ratio0, $ratio1;
although what I really meant was:
my $text = sprintf "Ratio Change: %7.4f => %7.4f\n", $ratio0, $ra +tio1;
and this gave me the following pair of duplicate warnings (since $ratio0 and $ratio1 aren't doing anything useful):
Useless use of private variable in void context at warn.pl line 59 +. Useless use of private variable in void context at warn.pl line 59 +.
Now I could turn off "use warnings" (and I'd also have to remove the -w switch if I'm running it under Unix/Linux), and my apparent problems would go away, right?

Well, not so fast!  It turns out that my output is not at all what I want either:

Ratio Change: %7.4f => %7.4f Ratio Change: %7.4f => %7.4f Ratio Change: %7.4f => %7.4f Start percentage ... 10.0000% End percentage ... 9.9900%
And if I'm disciplined enough to track down the cause of my warnings, by looking at line 59 and realizing what I really wanted was the sprintf statement, then I fix the underlying problem and get the desired output:
Ratio Change: 0.1000 => 0.1010 Ratio Change: 0.1010 => 0.1011 Ratio Change: 0.1011 => 0.1012 Ratio Change: 0.1012 => 0.1013 Ratio Change: 0.1013 => 0.1012 Start percentage ... 10.0000% End percentage ... 10.1202%
As another example -- this one illustrating the importance of "use strict" -- try changing both occurrences of "my $ratio0" to "$ratio0", and both occurrences of "my $ratio1" to "$ratio1":
Global symbol "$ratio0" requires explicit package name at ./warn.pl li +ne 26. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 27. Global symbol "$ratio0" requires explicit package name at ./warn.pl li +ne 27. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 30. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 30. Global symbol "$ratio0" requires explicit package name at ./warn.pl li +ne 37. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 38. Global symbol "$ratio0" requires explicit package name at ./warn.pl li +ne 54. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 55. Global symbol "$ratio0" requires explicit package name at ./warn.pl li +ne 57. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 57. Global symbol "$ratio0" requires explicit package name at ./warn.pl li +ne 59. Global symbol "$ratio1" requires explicit package name at ./warn.pl li +ne 59. Execution of ./warn.pl aborted due to compilation errors.
Yikes, that's a lot of errors!

Now, you could comment out "use strict" (and I'm sure it would be tempting to the beginning programmer who just wants his code to ship on time), but is the output really correct now ...?

Ratio Change: 0.1000 => 0.1001 Ratio Change: 0.1001 => 0.1000 Ratio Change: 0.1000 => 0.0990 Ratio Change: 0.0990 => 0.1000 Ratio Change: 0.1000 => 0.0990 Ratio Change: 0.0990 => 0.0991 Ratio Change: 0.0991 => 0.0992 Start percentage ... 0.0992% End percentage ... 0.0992%
Not a bit.  It might seem fine at first glance, but when you look carefully, you'll notice that both the start and end percentages are actually equal to the final ratio calculated by the subroutine ratio_change().

That's because the variables ratio0 and ratio1 in the main program need to be treated as distinct from the ones in the subroutine ratio_change(), where they serve a different function.   With "use strict" it's an error NOT to treat them that way.   Without "use strict", you're asserting "I know better -- let me decide which variables I want to be global, and which I want to be lexically-scoped!"  The problem is, if you don't get used to "my"-ing all your variables (even the ones at the top of the program, which will function like global variables to the rest of the file, so you have to be careful not to override them with non "my"-ed variables within blocks and subroutines), you'll eventually make a mistake you wish you hadn't.  Trust me.

The moral is this -- I got used to "use warnings" and "use strict" from the beginning, and since I'm unwilling to sacrifice their use, I have to respect the complaints they generate.  They have saved me time and time again from bugs that I can't even imagine, and all they ask in return is that you heed their advice as soon as you receive it.  Once you're in the habit of using them, ALWAYS, they will do more at a fundamental level to improve the discipline of your programming than anything else I know of!

Replies are listed 'Best First'.
Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by sauoq (Abbot) on Oct 04, 2005 at 20:07 UTC
    Once you're in the habit of using them, ALWAYS, they will do more at a fundamental level to improve the discipline of your programming than anything else I know of!

    I have to disagree here. Completely.

    I do generally think using warnings and strict is a good idea, especially for people who are relatively new to Perl. I don't, however, think that doing so will improve your programming at a fundamental level at all. In fact, it could be argued that strict and warnings will make you lazier because, well, you don't have to catch those errors if perl is going to catch them for you. More to the point, though, all they can do is help you catch some common errors... like typos, for instance. That's not going to result in programming improvement.

    They don't...

    • ... help you write better comments.
    • ... help you pick better function/variable names.
    • ... help you design better data structures.
    • ... help you choose better algorithms.
    • ... help you avoid logic errors.
    • ... help you improve the structure of your code.
    • ... etc.
    The only things they do help with are generally the problems that are easiest to fix anyway.

    I agree that they are useful tools but that's it.

    -sauoq
    "My two cents aren't worth a dime.";
    

      Well, I think use strict; does usually help to improve the structure of the code. If only because you have to think whether you want something to be global or local (lexical). Sure, you can declare all your variables on top of your script with "my" and keep all the bad habits, but it's somewhat less likely to happen then if you don't start using strict at all.

      So it's not going to make your code magically better, but it's going to nag you to make it better yourself.

      Jenda
      XML sucks. Badly. SOAP on the other hand is the most powerfull vacuum pump ever invented.

      The only things they do help with are generally the problems that are easiest to fix anyway.
      Agreed.  But those problems that are "easiest to fix" become so only after you've reached a certain state of enlightment with Perl.  My point is that you start out miles ahead by using these tools, and they give you invaluable habits which stick with you.  Furthermore, all of the very good bullet items you list are, in my opinion, things that you develop along the path to programming (be it Perl or any language).  I think we can both agree that nobody has a panacea for obtaining them in a short time.

      It's also true that the tools warnings and strict are most necessary for the beginning Perl programmer.  But, having said that, I'm not going to give them up anytime soon.  (:

        Miles ahead? I think you have a long way to go if you think that just adding "use strict" and "use warnings" gives you such a headstart.

        I always use warnings and strict (and know when to turn it off), but I've always considered them to be in the same class as the lights on my dashboard to remind me that the handbrakes are on, or that my oil level is low. Useful, but they don't make me a better driver. And they don't prevent accidents either.

        Perl --((8:>*
Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by itub (Priest) on Oct 04, 2005 at 18:54 UTC
    If you use warnings, it's usually not a good idea to use -w. When you use the older -w flag, you turn warnings on globally, even in modules you use that were not designed to run with warnings on, so you may get false positives. The warnings pragma gives you finer control, because you can turn the warnings on only where you want, and you can also control the types of warnings you get.

    See What's_wrong_with_-w_and_$^W in perllexwarn.

      Many people still use -w and for good reason. Some people like turning on warnings globally. Yes, it can be a good thing if you want that behavior. I am tired of people bashing it.

      Many big corporations with home-grown Perl modules still use the -w flag and wouldn't want it any other way.

        Many people still use -w and for good reason. Some people like turning on warnings globally. Yes, it can be a good thing if you want that behavior. I am tired of people bashing it.

        Well then I doubt you'll like to hear this: It doesnt actually work as you say it works. -w doesn't turn on warnings everywhere. It turns on warnings everywhere UNLESS a module or code uses lexical warnings. So if the module has "no warnings" then thats what happens.

        Maybe you meant -W?

        ---
        $world=~s/war/peace/g

        I agree that -w is still useful if that's what you really want and you are willing to accept the consequences. However, I've seen that in many, many cases, it is used out of ancient habit even when it's not the most appropriate. Using it together with warnings shows some of this confusion: if you want global warnings you just need -w, and if you want lexical warnings you just need warnings. If you use both, it's because you don't know what you want, or you don't understand the difference.

        (Note, here "you" is used as a generic pronoun, not refering to any specific person).

      Thanks for pointing that out, itub.  I admit that I still use -w out of my original force of habit, and have yet to include a module which complains because of it.  Certainly, I would prefer to be required to turn warnings off globally if I knew I had to, rather than the opposite.  But I can see where, as my usage of modules increases, I may need to occasionally give up my predilection for the global -w.
Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by McDarren (Abbot) on Oct 05, 2005 at 06:09 UTC
    When I first started learning Perl, the first thing the guy who introduced me to it drummed into my head is:

    Rule 1: "Every Perl program you ever write will use warnings and strict."
    Rule 2: "Refer to rule 1."


    As a beginner, I think this was absolutely the best advice I could have been given.
    Although I now understand that there are the odd times that you can get away without them, I still always do it out of habit and I'm yet to encounter a situation where it makes (more) sense to not use them.

    --Darren
Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by tilly (Archbishop) on Oct 05, 2005 at 05:42 UTC
    Another tip that will help you improve your code.

    Stop using prototypes.

    Yes, I am serious.

      Can you explain why?
        Without prototypes, the following two calls are equivalent:
        sub ratio_change {...} my @args = ($start_value, $start_total, $new_value, $new_total); ratio_change @args; # Same result as: ratio_change $start_value, $start_total, $new_value, $new_total;
        But with prototypes, they aren't:
        sub ratio_change ($$$$) {...} my @args = ($start_value, $start_total, $new_value, $new_total); ratio_change @args; # Eeks. Won't do what you think it does. ratio_change $start_value, $start_total, $new_value, $new_total;

        I don't shy away totally from using prototypes, but the only types I use are:

        sub foo (); sub foo ($); sub foo (&@); sub foo (\@@); sub foo (\%@);
        that is, I purely use prototypes to tell the parser how to parse things. I don't use it for argument checking (which is the typical use for '$$$$' style prototypes) as that get annoying fast - due to '$''s side effect of creating scalar context.
        Perl --((8:>*
Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by rvosa (Curate) on Oct 05, 2005 at 12:27 UTC
    warnings and strict don't make you a better coder any more than a spellchecker makes you a better writer. They're all certainly useful, but they don't lead to elegant designs, for example.
      I'm not sure that's true, for programmers, or for authors, either.

      From a career point of view, hiring an editor makes you a better writer, in the sense that your career will improve. Without one, you'll probably never get hired; it's very hard to see your own typos and spelling mistakes, and if you publish a newspaper full of typos and spelling mistakes, no one will take you seriously. Worse yet, you'll re-inforce your mistakes, and learn bad spelling.

      A spelling and grammer checker don't quite equal a good copy editor, but they're a decent first order approximation. Not using them will only hurt.

      Similarly, using strictness and warnings are a good first step towards good coding practices. No, they don't help you directly with your program content, but they help you make sure you spend your time writing content, and less time editing for correctness.

        Now that you mention grammar checkers, the following analogy suddenly occured to me: strict is to a spellchecker as warnings is to a grammar checker.

        In which sense? In my experience, both strict and the spelling checker point out real problems at least 90% of the time, making them highly effective and not too annoying. But warnings and the grammar checker are right less than 50% of the time, which can make them too annoying. ;-)

Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by Anonymous Monk on Oct 05, 2005 at 00:30 UTC
    I think your example is really poor. If I just added a line
    my $text = "Ratio Change: %7.4f => %7.4f\n", $ratio0, $ratio1;
    to my code (or replacing another one), and then my output shows
    Ratio Change: %7.4f => %7.4f
    I don't need a warning to know what is wrong.
Re: warnings and strict -- The 2 Best Ways You Can Improve Your Programming
by Anonymous Monk on Oct 04, 2005 at 18:18 UTC
    Ah, the eternal perlmonks dialectic. Use strict and warnings vs. I don't need no stinking hand holding.

    Edit by castaway - Swapped a tags for id:// links