strict
and warnings
Whenever debugging code,
make sure the strict
and warnings
pragmata are turned on.
Put these two lines
use strict; use warnings;
at the top of any program you're trying to debug, or may want to debug in the future. (If you think about it, that's every program ever, isn't it?)
The http://perldoc.perl.org/strict.html strict pragma forces you to use a number of features that allow Perl to find errors during compile time. First and foremost, under strict
, variables must be declared before they are used; in most cases, this means using my
:
use strict; my $foo = 7; # OK, normal variable print "foo is $fooo\n"; # Perl complains and aborts compilation
Without strict
, Perl would happily run the above programming, and you would be sad, wondering why $foo
didn't have a value. Enabling strictures can save a lot of headache induced by typos.
Additionally, strict
disallows the use of most barewords:
no strict; $foo = Lorem; print "$foo\n"; # Prints "Lorem" use strict; my $foo = ipsum; # Complains about bareword $foo = ( Lorem => 'ipsum' # OK, barewords allowed on left of => ); $SIG{PIPE} = handler; # Complains $SIG{PIPE} = \&handler; # OK $SIG{PIPE} = "handler"; # Also, OK, but above is preferred
Finally, enabling strict
throws a runtime error if you use http://perldoc.perl.org/perlref.html#Symbolic-references symbolic references:
no strict; $name = "foo"; $$name = "bar"; # Sets the variable $foo to 1 print "$name $$name\n"; # Prints "foo bar" use strict; my $name = "foo"; $$name = "bar"; # Complains: can't use "foo" as ref
The warnings
pragma enables a whole host of useful complaints from Perl, letting you know about things in your program that you most likely didn't intend:
use warnings; my $foo = ; $foo += 3; my $foo = 1; # Compains: redeclaration of variable my $bar = '12fred34'; my $baz = $bar + 1; # Complains: Argument "12fred34" isn't numeric # Complains: Name "main::baz" used only once
See the strict documentation strict and warnings for futher information. For some horror stories about leaving out strict, see http://www.perlmonks.org/?node_id=482733.
open
It's amazing how often you'll see people complaining that a piece of code doesn't work:
open( my $file, $filename ); while ( <$file> ) { ... }
and then complain that the while
loop is broken. The problem here is often that the file $filename
doesn't actually exist, and the open
fails, but without a check, you'll never know. Replace it with:
open( my $file, '<', $filename ) or die "Can't open $filename: $!";
diagnostics
Sometimes the warning message doesn't explain as much as you'd like. For instance, why might you get this warning?
Use of uninitialized value in string eq at /Library/Perl/5.8.6/WWW/Mechanize.pm line 695.
Try running the code again with
use diagnostics;
at the top of the program. Now the warning looks like this:
Use of uninitialized value in string eq at /Library/Perl/5.8.6/WWW/Mechanize.pm line 695 (#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. To help you figure out what was undefined, perl tells you what operation you used the undefined value in. Note, however, that perl optimizes your program and the operation displayed in the warning may not necessarily appear literally in your program. For example, "that $foo" is usually optimized into "that " . $foo, and the warning will refer to the concatenation (.) operator, even though there is no . in your program.
That's a lot more information to help you on your way finding the program.
Remember that you can specify modules and pragmata to be included on the command line, so you don't even have to edit your source code to use diagnostics
. Run it again with the -M
command line switch:
perl -Mdiagnostics mycode.pl
Sometimes you'll get a warning but you can't tell how it got there. It'll say something like:
Use of uninitialized value in string eq at /Library/Perl/5.8.6/WWW/Mechanize.pm line 695.
So you can go see what the code at line 93 of that module is doing, but it doesn't tell you what your code was doing to get to that point. What you'd like to see is a trace of what subroutines were called.
When Perl calls die
or warn
, it goes through the subroutines specified in $SIG{__DIE__}
and $SIG{__WARN__}
, respectively. If you modify those to be more useful functions than CORE::die
and CORE::warn
, you've got a handy debugging tool. In this case, use the Carp
module's confess
function.
At the top of your program, add these lines:
use Carp qw( confess ); $SIG{__DIE__} = \&confess; $SIG{__WARN__} = \&confess;
Now, when the code calls warn
or die
, the Carp::confess
function handles it. In this case, confess
prints the original warning, followed by a stack trace, and then stops execution of the program.
Use of uninitialized value in string eq at /Library/Perl/5.8.6/WWW/Mechanize.pm line 695. at /Library/Perl/5.8.6/WWW/Mechanize.pm line 695 WWW::Mechanize::find_link('WWW::Mechanize=HASH(0x180e5bc)', 'n', 'undef') called at foo.pl line 17 main::go_find_link('http://www.cnn.com') called at foo.pl line 8
Now we have much more information to debug our code, including exactly what functions were called, and what parameters were passed. From here, we can easily see that the third argument to find_link
is undef
, which is a great place to start investigating.
If you don't want to go through all the hoohah with overriding signal handlers, you can install the CPAN module Carp::Always.
After installing Carp::Always, adding one line to your code
use Carp::Always;
or calling your program with -MCarp::Always
on the command line will always give a stack trace.
Submit a PR to github.com/petdance/perl101
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.