How to debug a Perl program
Archive - Originally posted on "The Horse's Mouth" - 2006-06-04 07:37:19 - Graham EllisHave you every written a Perl program that doesn't perform as you would wish? Yes, everyone who's written a Perl program has done that. Once any syntax errors have been corrected, you run your program for the first time and you check - VERY carefully - the results. Any errors, and the patterns of errors, will often lead you quickly to coding errors and as you gain experience, you'll fix more and more bugs quicker and quicker this way.
But what about those 'reluctant' bugs - those things that have you scratching you head thinking "surely this cannot be happening". You need further clues, and Perl offers a number of facilities - some very simple - to help you.
1. You should run your code with the -w command line option, or with
use warnings;
specified at the top of your code. Both of these operations cause Perl to check at both compile and run time that you're not specifying something that's technically valid, but unlikely to be what you intended - it'll pick you up on uninitialised variables, variable names that only occur once, bare words that should probably have a $ in front of them, and so on.
2. The humble print statement can be very revealing - add in a few extra output statements for intermediate variables and you'll soon start to see where abouts in your code its behaviour starts to deviate from what you had intended.
3. The Data::Dumper module allows you to "pretty print" data structures if you want to go beyond the print statement - perhaps you have whole lists or hashes that you want to dump out? (Link - source example using Data::Dumper)
4. Perl comes with an interactive debugger - run Perl with the -d option if you want to run this way. There's a tutorial on this in the perl distribution - run perldoc perldebtut at the command line for more details.
If these initial four ideas don't cut it for you, there are other things to consider too.
Personally, if I'm writing a difficult piece of code I will start off with
$trace = 0;
at the top, and further down my code I'll add in statements such as
$trace and print "At point X, counter is $n, total $tot\n";
which form a report / debug facility if run; all I need to do is to switch my initial assignment to a true value, and I've turned on a tailored debugging mode. We use a similar technique on our web site pages under both PHP and Perl - where we accumulate reports using the .= operator and output them at the end of our web pages - users rarely notice and it's sometimes a huge help to us when we're looking to resolve browser specific issues or data driven problems.
Some advocates suggest that you should
use strict;
in all your code as a debug tool. I'm going to disagree. Rather, it is good practise to use the strict pragma in all .pm files that you'll be including but that should be as a matter of course and not just as a debugging aid. And I will typically omit the pragma from my main code / main program.
There's various CPAN modules to help you too - ptkdb and Devel::ebug provide a GUI to help debug, and programatic hooks for you to add your own debug facilities, if that's what you want.
And finally, there are commercial debuggers such as ActiveState's Komodo.
My own favourite toolkit - what I suggest to course delegates ...
a) Comment your code well, use sensible variable names to reduce bugs in the first place.
b) Think about your code - design it well (if informally) with appropriate UML diagrams to reduce design errors in the first place. (Link - .pdf training module on this)
c) Run with the -w command line option at least a few times.
d) use strict; within modules.
e) Add in print or Data::Dumper calls, perhaps under a $trace option, if you've got a piece of large / complex / reluctant code.
The other options? Great to have them available from time to time ...