Home arrow Perl Programming arrow Perl Debuggers in Detail

Perl Debuggers in Detail

In this second part of a two-part series on debugging Perl, we will go beyond the author's favorite debugger and look at a number of alternative Perl debuggers. This article is excerpted from chapter four of the book Mastering Perl, written by Brian D Foy (O'Reilly; ISBN: 0596527241). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

TABLE OF CONTENTS:
  1. Perl Debuggers in Detail
  2. perl5db.pl
  3. Alternative Debuggers
  4. Devel::ebug
  5. Other Debuggers
  6. Summary
By: O'Reilly Media
Rating: starstarstarstarstar / 3
July 31, 2008

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Wrapping Subroutines

I donít have to copy a module file to change its behavior. I can override parts of it directly in my code. Damian Conway wrote a wonderful module called Hook::LexWrap to wrap a subroutine around another subroutine. That means that my wrapper subroutine can see the arguments coming in and the return values going out. I can inspect the values, or even change them if I like.

Iíll start with my simple example program that adds a couple of numbers. As before, it has some problems because Iím passing it the wrong arguments since I canít tell the difference between $n and $m, and have used $n twice in my call to add. Just running the program gives me the wrong answer, but I donít know where the problem is:

  #!/usr/bin/perl
 
# @ARGV = qw( 5 6 );

  my $n = shift @ARGV;
  my $m = $ARGV[0];

  print "The sum of $n and $m is " . add( $n, $n ) . "\n";

  sub add
         
{
         
my( $n, $m ) = @_;

          my $sum = $n + $m;

          return $sum;
          }

I donít want to change anything in the code, or, I should say, I want to look at whatís happening without affecting the statements that are already there. As before, I want everything back to normal when Iím finished debugging. Not editing the subroutine makes that easier.

The Hook::LexWrap gives me a chance to do something right after I make a subroutine call and right before the subroutine returns. As the name suggests, it wraps the subroutine with another one to provide the magic. The Hook::LexWrap::wrap function takes the name of the subroutine it will wrap, add in this case, and then anonymous subroutines as pre- and posthandlers:

  #!/usr/bin/perl

  use Hook::LexWrap qw(wrap);

  my $n = shift @ARGV;
  my $m = $ARGV[0];

  wrap add,
         
pre  => sub { print "I got the arguments: [@_]\n" },
         
post => sub { print "The return value is going to be $_[-1]\n" }
          ;

  # this line has the error
  print "The sum of $n and $m is " . add( $n, $n ) . "\n";

  sub add
         
{
         
my( $n, $m ) = @_;

          my $sum = $n + $m;

          return $sum;
          }

The prehandler sees the same argument list as my call to add. In this case I just output the list so I can see what it is. The posthandler gets the same arguments, but Hook::Lex Wrap adds another element, the return value, on the end of @_. In the posthandler,
$_[-1] is always the return value. My program now outputs some useful debugging output, and I see that Iím passing the same argument twice:

  $ perl add_numbers.pl 5 6
  I got the arguments: [5 5 ]
  The return value is going to be 10
  The sum of 5 and 6 is 10

In that output, notice the space after the last 5. Since wrap added an element to @_, even though itís undef, I get a space between it and the preceding 5 when I interpolate the array in the double-quoted string.

Hook::LexWrap has the magic to handle all the calling contexts too. Itís smart enough to handle scalar, list, and void contexts. In list context, that last element of @_ in the posthandler will be an array reference. In void context, it wonít be anything.

It gets even better than that, though. Hook::LexWrap actually adds that extra element to @_ before it does anything. Look at the last output carefully. After the second argument, thereís a space between the second 5 and the closing square bracket. Thatís the space between 5 and the undef value of the extra element in @_.

In the prehandler, I can assign to that element, signaling to Hook::LexWrap that it should assume that it already has the return value, so it doesnít need to actually run the original subroutine. If the subroutine isnít doing what I need, I can force it to return the right value:

  #!/usr/bin/perl

  use Hook::LexWrap;

  my $n = shift @ARGV;
  my $m = $ARGV[0];

  {

  wrap add,
         
pre  => sub {
                  print "I got the arguments: [@_]\n";
                  $_[-1] = "11";
                 
},
         
post => sub { print "The return value is going to be $_[-1]\n" }
         
;
  print "The sum of $n and $m is " . add( $n, $m ) . "\n";
  }

  sub add
         
{
          my( $n, $m ) = @_;

          my $sum = $n + $m;

          return $sum;
          }

Now that Iíve assigned to $_[-1] in my prehandler, the output is different. It doesnít run the subroutine or the posthandler, and I get back 11:

  $ perl add_numbers.pl 5 6
  I got the arguments: [5 6 ]
  The sum of 5 and 6 is 11

With my fake return value, I can give myself the right answer and get on with the right program, and do it without changing the subroutine I want to investigate. This can be especially handy if Iím working on a big problem where other things are broken, too. I know what I need to return from the subroutine so I make it do that until I fix the other parts, or at least investigate the rest of the program while the subroutine returns what it should. Sometimes eliminating a source of error, even temporarily, makes it easier to fix other things.



 
 
>>> More Perl Programming Articles          >>> More By O'Reilly Media
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PERL PROGRAMMING ARTICLES

- Perl Turns 25
- Lists and Arguments in Perl
- Variables and Arguments in Perl
- Understanding Scope and Packages in Perl
- Arguments and Return Values in Perl
- Invoking Perl Subroutines and Functions
- Subroutines and Functions in Perl
- Perl Basics: Writing and Debugging Programs
- Structure and Statements in Perl
- First Steps in Perl
- Completing Regular Expression Basics
- Modifiers, Boundaries, and Regular Expressio...
- Quantifiers and Other Regular Expression Bas...
- Parsing and Regular Expression Basics
- Hash Functions

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: