Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Use strict warnings and diagnostics or die

by tachyon (Chancellor)
on Jun 11, 2001 at 23:37 UTC ( [id://87628]=perlmeditation: print w/replies, xml ) Need Help??

Alternate title: Read this if you want to cut your development time in half!

Note this article was written as a resource for the New Monks Info Page node in response to some wonderful feedback from fellow monks. It is designed as an easy read for new monks who may need easing into the world of strict and warnings. I have posted to meditations so I can edit it in response to monk feedback as has happened with previous nodes. I guess tutorials or Q&A will be its final resting place.

Perl is a wonderful language. As an interpreted language your first program can be as simple as this old classic:

print "Hello world\n";

When you compare this to the same program in c which also needs to be compiled before it will run the attraction seems obvious.

#include <stdio.h> 
 
int main()  
{    
    printf("Hello World!\n");  
    return 0;
} 

As soon as you move past the trivial and start coding longer programs you rapidly discover the concept of the bug. All newer distributions of the Perl language include a number of pragmas to help you with the inevitable debugging. Debugging might be defined as the final step required to transfer your idea of what you want a computer to do into a set of instructions that the computer understands (and which it can execute) to make your idea a practical reality. Sometimes some rather more crusty descriptions come to mind.

Perl has three pragmas specifically designed to make your life easier:

use strict;
use warnings;
use diagnostics;

If you don't understand the meaning of the word pragma don't worry, it doesn't matter, it is just a jargon term that encompasses these three features (amongst others). We will cover each pragma in turn, clearly stating how and why you should be using it. The benefits far outweigh the short learning curve. Note that for the short, quick and dirty solutions that Perl does so easily you don't need them but as your code gets longer and/or in a production environment they are invaluable. "If you intend on building production-level code, then "use strict" and "use warnings" should be disregarded only if you know exactly why you are doing it" - dragonchild

Perl has a great help thy neighbour culture, but you will quickly discover the response you receive to any request for help (regardless of the forum) will be far better if you have tried to help yourself. Using the strict, warnings and diagnostics pragmas is generally deemed to fall into this self help category. If you are not using these pragmas the responses you receive to a help request will vary from the helpful "OK, here is your problem on line xxx" to the more pointed "Don't ask a person to do a machine's work" to the succinct RTFM.

Don't expect a person to do a machine's work can be explained thus: "Perl provides a lot of help to debug your program and get it working via the strict, warnings and diagnostics pragmas. Perl is very good at this task. If you can't be bothered doing this basic thing then why should I expend my valuable unpaid time and effort to help you?" Whilst the delivery of this response may vary from the gentle urging to the less subtle FOAD it is still very practical, and based on thousands of years of combined experience. Once you get in the habit of using these pragmas you will find Perl isolates problems automatically for you and can reduce development time by half or more (given that most of the time spent developing code is spent debugging).

So let's get down to it!

Bondage and discipline - use strict;

To activate the strict pragma we add the line use strict; just below the shebang line.
#!/usr/bin/perl
use strict;
Use strict actually consists of these three separate pragmas:
use strict 'vars';
use strict 'refs';
use strict 'subs';

Each of these does a different thing as we will see. You *can* activate each of these separately, but most programmers prefer to activate all three with a simple use strict;. You may deactivate a pragma using:

no strict;		# deactivates vars, refs and subs;
no strict 'vars';	# deactivates use strict 'vars';
no strict 'refs';	# deactivates use strict 'refs';
no strict 'subs';	# deactivates use strict 'subs';

OK so now we know how to turn them on and off what do they actually do?

use strict 'vars';

By far the most useful in general coding is the use strict 'vars'; pragma. When this is active Perl complains if you try to use a variable that you have not previously declared.

$foo = 'bar'; 	# OK

use strict 'vars';
$foo = 'bar'; 	# Triggers an error

If we try to run the second example we will get an error like:

Global symbol "$foo" requires explicit package name at script line 2.
Execution of script aborted due to compilation errors.

Fantastic you say, my simple program is now broken, and for what. For your sanity that's why. Consider this slightly longer (silly) example that counts down from ten then calls a sub liftoff. The liftoff sub is designed to count the number of liftoffs:

$count = 10;
while ($count > 0) {
    print "$count ";
    $count--;
    liftoff() if $count == 0;
}

sub liftoff {
    $count++; # count liftoffs
    print "This is liftoff $count\n";
}

Perfectly valid code, but if these two snippets were separated by other code the fact that this is an infinite loop might be harder to spot, especially without the print statements. The problem occurs because of the global variable $count, which is changed within the liftoff sub. As a result the while loop never exits, and repeatedly calls the liftoff sub. Whilst this is very simplified the fact is that common variables like $count, $line, $data, $i, $j etc are often used many times within a program. If we do not localise them to where they are used some very nasty bugs can arise. These bugs can often be hard to find.

Over time programmers have come to the realisation that global variables are in general a bad idea. A variables "scope" defines where it can be seen in the program - generally the narrower the better. A global variable can be seen and modified everywhere. A lexically scoped variable can only be seen within its lexical scope. To fix our errant liftoff sub we localise the $count variables to where the are needed via a "my" directive.

my $count = 10;
while ($count > 0) {
    print "$count ";
    $count--;
    &liftoff() if $count == 0;
}

{ 
    # scope our variable $count via a closure
    my $count;
    sub liftoff {
        $count++; # count liftoffs
        print "This is liftoff $count\n";
    }
}

liftoff();
liftoff();
liftoff();
liftoff();

Now that we have localised our $count variables this prints:

10 9 8 7 6 5 4 3 2 1 This is liftoff 1
This is liftoff 2
This is liftoff 3
This is liftoff 4
This is liftoff 5

So as desired each time the liftoff sub is called it increments our counter. The lexical scope of a variable declared via my is most simply explained by example:

my $count = 10;
print "$count\n"; 	# $count is 10 here

{
    my $count = 5;
    print "$count\n";   # $count is 5 here 
}

print "$count\n"; 	# $count is 10 here again

Astute readers will note that because we define $count at the top of this code it is effectively a global variable. This is quite true in a limited sense and often how programmers initialy deal with pacifying use strict. In this case we have a $count with a wide scope and another *different* $count with a narrow scope. Talk about have your cake and eat it to!

In simple terms a lexical scope is the area from a opening curly to the corresponding closing curly. If you declare a variable with my within a lexical scope it only exists within the innermost lexical scope. Outside this scope it does not exist. For example:

{
    my $count = 10;
    print "$count\n";
}

print "\$count is zero or undefined!\n" unless $count; 

Prints:
10
$count is zero or undefined!

For an extensive expert discussion of scoping variables see Coping with Scoping and Seven Useful Uses of Local by Mark-Jason Dominus.

use strict 'refs';

The use strict 'refs' pragma prevents you from using symbolic references. References are a very useful but somewhat advanced technique. You can write plenty of useful code without understanding them but eventually you will discover how they can make life much easier.

Here are two trivial examples of references (sorry that they do not make the case for using references obvious):

my $foo = "bar";
my $bar = "foo";

my $ref = \$foo;

# hard reference
print $$ref;        # prints 'bar'

# symbolic reference
print $$bar;        # also prints 'bar'

So what gives? In the first case we create a hard reference to the variable $foo. We then print the value in $foo by dereferencing it via the $$ construct. In the second case what happens is that because $bar is not a reference when we try to deference it Perl presumes it to be a symbolic reference to a variable whose name is stored in $bar. As $bar contains the string 'foo' perl looks for the variable $foo and then prints out the value stored in this variable. We have in effect used a variable to store a variable name and then accessed the contents of that variable via the symbolic reference.

Excellent you say, I wanted to know how to do that. Trust me it is a very bad idea. Besides making your code rather difficult to understand it can lead to some very difficult debugging. For a full discussion on why this is a really bad idea see Why it's stupid to use a variable as a variable name by one of my favourite guru's Mark-Jason Dominus again.

Getting back to our example had the use strict 'refs' pragma been active then Perl would have let us know about this dangerous problem via a message along the lines: Can't use string ("foo") as a SCALAR ref while "strict refs" in use at test.pl line 12.

use strict 'subs';

In Perl you can call a subroutine in three ways:

mysub;
mysub();
&mysub;

You can use the first form because perl assumes any bareword (ie not a key word and not quoted) must refer to a user defined subroutine. This is fine but what if you have a typo:

sub my_sub {
    print "Hello World\n";
}

mysub;

This fails to print the expected "Hello World" because of the typo. Normally it would compile and run just fine, it just wouldn't work. However under use strict 'subs' perl will let us know we have a problem with a message like:

Bareword "mysub" not allowed while "strict subs" in use at test.pl line 5.
Execution of test.pl aborted due to compilation errors.

Baby help me please - the use warnings pragma

To activate the use warnings pragma you can do either of the following:

#!/usr/bin/perl -w
use warnings;	# only on Perl 5.6.0 and greater

Under Perl 5.6.0 and higher you can deactivate warnings (lexically scoped) like this:

no warnings;

First please note that "use warnings;" and "no warnings;" require Perl 5.6.0 or greater. Many people do not yet use this version so for maximum portability "-w" is preferred. Even though Win32 systems do not understand the concept of the shebang line Win32 Perl will look at the shebang and activate warnings if the "-w" flag is present so this works cross platform. For a full discussion see use warnings vs. perl -w. For Win32 users on *nix the operating system will examine the first two bytes of an executable file for the "#!" sequence and if found execute the file using the executable found on the path that follows the "#!".

Unlike strict when perl generates warnings it does not abort running your code, but it can fill up your screen :-) Here is a simple example of how warnings can *really* help:

$input_received = <STDIN>;
exit if $input_recieved =~ m/exit/i;
print "Looks like you want to continue!\n";

Three lines - what could be easier. We get some input from STDIN and exit if the user types exit. Otherwise we print something. When we run the code we find that regardless of what we type it prints. Why no exit?? Lets add warnings and see what happens:

#!/usr/bin/perl -w

my $input_received = <STDIN>;
exit if $input_recieved =~ m/exit/i;
print "Looks like you want to continue!\n";

Name "main::input_received" used only once: possible typo at test.pl line 3.
Name "main::input_recieved" used only once: possible typo at test.pl line 4.
test.pl syntax OK

So we have a syntax error, fix that and we are off and running. If we were using strict the code would not have run in the first place but that's another story. Typos like this can be hard for humans to spot but perl does it in a jiffy.

Use of a what in a where like how? - use diagnostics

When you first start to use warnings some of the messages appear quite cryptic. Don't worry, the "use diagnostics;" pragma has been designed to help. When this is active the warnings generated by "-w" or "use warnings;" are expanded greatly. You will probably only need to use diagnostics for a few weeks as you soon become familiar with all the messages!

To finish off, here is another example:

my @stuff = qw(1 2 3 4 5 6 7 8 9 10);
print "@stuff" unless $stuff[10] == 5;

If you run this code it runs OK, or does it? Sure it prints the array but there is a subtle problem. $stuff[10] does not exist! Perl is creating it for us on the fly. Use warnings catches this subtle trap but if we add the use diagnostics; pragma we will get a blow by blow description of our sins.

use warnings;
use diagnostics;
my @stuff = qw(1 2 3 4 5 6 7 8 9 10);
print "@stuff" unless $stuff[10] == 5;

With warnings on the error is caught and with diagnostics on it is explained in detail.

Use of uninitialized value in numeric eq (==) at test.pl line 4 (#1)
    
    (W uninitialized) An undefined value was used as if it were already
    defined.  It was interpreted as a "" or a 0, but maybe it was a mistake.
    To suppress this warning assign a defined value to your variables.

The Bad News

So now that I have waxed lyrically about the merits of these three pragmas it is time to give you the bad news. Fortunately there is not much.

Learning Curve

As with anything new it takes a while to get used to the strictures of these pragmas. The overwhelming majority of Perl coders appreciate the benefits, but there is a learning curve. Use diagnostics has no learning curve - it is just to help you understand the warnings generated. The warnings are fairly self explanatory (especially with use diagnostics) and after a while you grow very used to all the free help the offer, especially on the typo front.

Use strict requires some understanding of scoping your vars. I have already given you links to some of the best articles available on this topic so you have some good help available. Initially using strict is a pain. The pain is short and the benefits long so I encourage you to persevere. You will be over the hump in no time.

CGI

For CGI scripts to work you need to output a header. Typically you will have:

print "Content-type: text/html\n\n";

occuring early in your script. Errors from warnings and strict will generally be output before this resulting in a 500 internal server error due to malformed headers. I suggest running your script from the command line first to weed out the warnings and or adding:

use CGI::Carp 'fatalsToBrowser';

Note you want to comment this out of the production code to avoid compromising security.

If you have reached here you are already well on the road to Perl nirvana. I hope you enjoy the journey.

tachyon

Replies are listed 'Best First'.
Re: Use strict warnings and diagnostics or die
by dragonchild (Archbishop) on Jun 12, 2001 at 00:13 UTC
    Very good article!

    However, I'd like to make the comment that Perl is used for a number of different purposes. The various pragmas aren't always needed, or even desired.

    When Perl is used for CGI or applications development, especially if one is designing production code, then use every single pragma you can find. This is most especially true when developing production modules or scripts. (It'd be nice if every CPAN developer did this as well, but that's another story.)

    However, a lot of people use Perl as a nifty version of awk or sed. For them, strict and warnings are a burden, not a benefit.

    I'd modify your article to say that if someone is intending on building production-level code, then "use strict" and "use warnings" should be disregarded only if that person knows exactly why they are doing so (Some code is actually strengthened by turning off strict refs, but that's to get around a minor problem with Perl's OO implementation.)

Re: Use strict warnings and diagnostics or die
by pmas (Hermit) on Jun 12, 2001 at 00:41 UTC
    Excellent article. But...

    I am afraid that it is too much reading for newbies (some are too busy even to register)... : )

    I think it might be good idea to have special 'obstacle course' for newbies with experience less than (put you guess here) and anonymous monks before allow them to post something. Page like:


    So you want to ask for help?

    Fine.

    But before you dare to ask somebody to spend his/her valuable time to look into your code for free, please do your homework (and keep your reputation intact and avoid flames and RTFM response, too):

    link : "Are you 100% sure you have '-w' after shebang and 'use strict' " ==> will allow to continue on next 'obstacle' page;

    link "I am not sure if I do or why I should" will link to this explanation.

    If you are complete beginner, you may want to subscribe to perl beginners list:

    http://lists.perl.org/showlist.cgi?name=beginners

    There are many experts specializing to answer questions from beginners and beginners only.

    Please read all FAQ and come back. We enjoy answering tricky questions...

    ... end of page ...


    On next page can be question about using CGI.pm, etc. So we can guide new monk through FAQ, making sure s/he read all relevant FAQ before posting. I hope people do not want to be a cheaters, will not just click through.

    So we will force newbies to read and think - and maybe to register some anonymous guys.

    I hope this is not too much "anti-newbie". Just wanted to suggest interface which makes most sense - IMHO.

    pmas

    To make errors is human. But to make million errors per second, you need a computer.

Re: Use strict warnings and diagnostics or die
by tachyon (Chancellor) on Jun 12, 2001 at 22:34 UTC

    Yup mpolo, I agree it is too long. Waay tooo long. I got totally manic and let my fingers go wild for a hour or so. As with the original New Monks which got pared down to the New Monks Info Page this page needs a serious edit.

    The problem is that use strict is a pain when you first use it a it breaks working code. Hell my sysadmin advised me not to use it! From a new user's perspective the obvious question is "Why do I need to use strict, it breaks my working code?"

    While "Because we say so and we know Perl and you don't and you'll thank us all one day and we won't help you if you don't help yourself by doing it etc" is an accurate if gramatically awful response it does not explain how it helps. Giving short examples makes it obvious but adds length. To short and you lose the explanation, to long and you lose the readers interest. Kinda Catch 22.

    Having now had 24 hours to sleep on it I will get out the axe and hack out all the bits that can wait trying to distill a bare essence of truth out of this. When it's done I'll post it with a link to the full version here. I've had plenty of /msg feedback on what can go but welcome more suggestions of what to keep and what to axe. Another perspective always helps you know...

    Yes I like XPs as much as the next Monk. IMHO the tangible reward (via XPs) for the help we all offer is what makes this site so much more rewarding and fun than usenet. At the Monastery even if no one posts a thank you or sends a /msg vis same you get some positive (or negative) feedback on your efforts. As well as promoting a helpful flame free attitude the fact that you can get -ve XPs (and generally do for posting a RTFM reply) encourages friendly behaviour from the Monks and makes for a much more pleasant environment for all of us.

    Off to sharpen the axe

    cheers

    tachyon

      > While "Because we say so and we know Perl and you don't
      > and you'll thank us all one day and we won't help you if
      > you don't help yourself by doing it etc" is an accurate
      > if gramatically awful response it does not explain how
      > it helps. Giving short examples makes it obvious but
      > adds length.

      First off, in regard to length, I'm going to add my voice to those who say that strict should be in a separate document from warnings and diagnostics. That would help with the length problem, and some people such as myself who understand warnings perfectly are a big hazy on the value of strict. Splitting the thing up would make it easier to read only the needed document.

      Second, I want to disagree with your assessment that the short examples make the value obvious, specifically in the case of strict. I don't have the level of experience of some people here, but I'm not exactly a complete Perl newbie either, and the value of strict (especially strict vars) is not evident to me. Further, I was under the impression from the Camel (2nd ed) that there is no consensus among the authors as to whether use strict is really useful, let alone important, and that it was kept optional precisely because some experienced people don't like it. What I still want to understand is the reasoning behind people who consider it so important, but neither the example nor the explanation helps. If anything, the example makes matters worse because any newbie can see that problem would have been caught by warnings, without any need for strict. You need an example of something warnings would not have caught, that strict does prevent, that's clearly an error but could at least potentially be hard to spot.

      I want to understand what people see in strict, but this node as it currently stands isn't doing that for me.

       -- jonadab

        Strict vars forces you to scope your variables. This is a very good thing. If you don't get why you have probably not read the coping with scoping link and/or worked on debugging code with over 1000 lines and wide use of globals.

        Here is a very simple 'vars' typo example that will be caught by strict, will not be caught by warnings and is not 'obvious'. Typos with varnames are the statistically most common cause of software bugs....

        use warnings; #use strict; my $recieved = 0; print "Do you get it (y/n)?"; $received = <>; print "Got $recieved" if $received =~ /y/;

        Strict and warnings are complementary - they have some overlap but the overlap is imperfect, thus the usefulness of both comes into play.

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      I do not agree with Mpolo's suggestion to split this into three tutorials (entitled use strict; use warnings; and use diagnostics;). If you really feel like it needs to be broken up into smaller pages, you should start with a general overview. Then, the second (and possibly third) page(s) could cover the subjects in greater detail. Tutorials are generally geared toward newbies who do not alway benefit from all the details at once (not to say that the details should be skipped). Crawl->Walk->Run kind of thing.

      The problem is that use strict is a pain when you first use it a it breaks working code. Hell my sysadmin advised me not to use it! From a new user?s perspective the obvious question is Why do I need to use strict, it breaks my working code?

      The tutorial is designed for people without a lot of experience in Perl (i am assuming... since it is a lesson on -w, use diagnostics, and use strict). These are the people that *should* be making sure to include the warnings and diagnostic functions. Even experienced programmers new to Perl should probably enable these functions until they get comfortable with the language.

Re: Use strict warnings and diagnostics or die
by mpolo (Chaplain) on Jun 12, 2001 at 10:59 UTC
    As commented by another, this is awfully long for a new user. (At least at one blow.) What if we split this into three tutorials (entitled "use strict;" "use warnings;" and "use diagnostics;")? Then we would be able easily link the appropriate chunk and maybe have a chance that it gets read. Of course, I have a few suggestions...

    <mode value="pedantic">

    In "use strict 'subs';", I suggest adding a sum-it-up line. "So, when this pragma is active, Perl will no longer assume that barewords are subroutine calls. You will need to either tack on parentheses (an argument list) or explicitly prefix the subroutine name with the & funny character." (or equivalent...)

    In "use warnings;" your explanation of the shebang to Windows users needs some punctuation. I suggest putting the sentence in parentheses and adding a colon after "For Win32 users".

    In the summary for that section, you say "So we have a syntax error...", but that's not true. We have a typing error -- as your warnings output indicates, the syntax was OK.

    </mode>

    P.S. Are you sure this isn't just an elaborate XP-gaining scheme?

Re: Use strict warnings and diagnostics or die
by 2mths (Beadle) on Jan 25, 2002 at 21:25 UTC
    As an initiate both to the monastory and Perl I don't know if I'm allowed to post yet but...

    I found this page very usefull and informative. It's explained several things that I didn't understand and really should have. If I could vote for it I would.

    Regarding the comments about being too long. I can see why some may say that but I found it a reasonable length. It's not a solid block of text and doesn't take too long to traverse. If someone isn't prepared to put a little effort into their learning why do they deserve the rewards it gives? The page could be slightly tweaked but I don't feel it's my place to make specific criticism, it might be me that's actually at fault ;-)

    ...Oh and I like this preview business
Re: Use strict warnings and diagnostics or die
by Jenda (Abbot) on Jun 11, 2002 at 14:50 UTC

    One little thingie ... use diagnostics; slows down the execution. Therefore I'd recomend using it only during development and only if you do not understand some warning or error message. Besides ... you can always find the longer explanations in perldoc perldiag.

    use strict; and use warnings; on the other hand can never be overrecomended (hope there is such a word in English).

      Jenda@Krynicky.cz

Re: Use strict warnings and diagnostics or die
by agentv (Friar) on Dec 16, 2002 at 21:56 UTC

    I jumped in here to respond to all of the comments that the tutorial was too long. My first reaction was, "How committed would the reader have to be to learning Perl better to be willing to invest the time to read this?"

    I timed it, and it took me about 12 minutes to read this article. I did find myself distracted a few times, and I did take some time to consider the implications of the exercises that tachyon demonstrates in the article.

    In the end, I agree that the article could use a little trimming and tightening, but I still do not feel that it's *too* long. If someone is not willing to invest 12 minutes to read something that might make their code more robust in the future, then they deserve to waste all of the time with the single-step debugger, and all of the time it takes to write up a message here only to be met with the ubiquitous RTFM response. (Although the lack of that phenonmenon is what keeps me coming back to PM often.)

    In the Dot-Com heyday, the streets were clogged with those who desired to leverage technical expertise (somehow) without making any investment of skull-sweat whatsoever. Most of those people have gone back (deservedly) to jobs where they process one-hour film, or hand espresso out the window to people in their SUVs. What is left of us (in this community) are those who understand that a little study is what it takes to make a better Perl (or anything) programmer.

    So my conclusion is that this a good and worthwhile article. Like most things, it could stand to be tightened up about 15-20% so that it stays on-point more and so that all of the primary points are crystal clear. But overall tachyon, I'd say that this is the sort of article that makes me wish that we had a continuum to vote for articles. Something like three good, three bad, and a neutral. I'd give this three +++ even before editing.

    ...All the world looks like -well- all the world, when your hammer is Perl.
    ---v

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://87628]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-12-11 12:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which IDE have you been most impressed by?













    Results (63 votes). Check out past polls.