Data::Dumper Debugging
I've never really used the Perl debugger much (maybe I should learn?) and usually resort to lots of use Data::Dumper; print Dumper($somevar);
statements to help me understand what's going wrong with a piece of code.
However, what I often find is that $somevar
contains exactly the data I expected it to contain. So the problem must be another variable? Or maybe there's a function which isn't returning what I expected it to? Or maybe one of my if
statement has jumbled logic? So I need to change my print Dumper(...)
statement and re-run the script.
Anyway, sick of that, and inspired by a question on StackOverflow I've released Pry, a really tiny wrapper around DOY's Reply REPL. Using Pry, you can run your script, and drop into a REPL at the point where you suspect things are going wrong. Once in the REPL you can inspect any lexical variables which are in scope (thanks, PadWalker!), or peek at the call stack (thanks, Devel::StackTrace!); you can even call functions and methods to see what's going on.
So if you, like me, have never managed to figure out breakpoints, and watches, and whatever other thingies a proper debugger has to offer, but are getting frustrated by the limitations of Data::Dumper-based debugging, give Pry a try!
Neat. There is actually a simple way to do this in the debugger though. You can just put $DB::single = 1; in your code where you want it to stop and drop into the debugger shell.
Nice, although I wouldn't write
use Data::Dumper; print Dumper($somevar);
in the first place, I'd write:
use Data::Dump; dd $somevar;
or:
use Data::Printer; p $somevar;
...which are not only more convenient to type, but also produce much prettier output.
Data::Printer produces nice output, and I used to use it quite a lot. I got frustrated by a couple of things though.
For objects it shows a list of methods they have - awesome, right? However, it fails to show any inherited methods. This breaks encapsulation. (Outside the class definition itself, you shouldn't care whether a method has been implemented directly by that class or inherited from a superclass.)
Also the prototype on the
p()
function, and different behaviour in void and non-void contexts, is all just a tiny bit too unpredictable for me.Have you taken a look at Carp::Reply?
I've used it to similar effect, probably worth a SEE ALSO.
Yes, I like Carp::Reply. It only kicks in when you reach an exception though. I like the idea of dropping into a REPL, poking around, exiting the REPL and resuming execution from there.
Useful if you want to, say, poke around at each stage of a loop.
Data::Printer outputs to STDERR which means you can't pipe the output to a pager without extra work. At that point Data:Dumper ends up requiring less typing.
Perl warnings go to STDERR anyway, so I'm already in the habit of:
@Toby Inkster
You're right, Data::Printer has some quirks.
The prototype thing is a trade-off; it allows
p
to treat an array variable with a single value differently than a scalar variable, and an array differently than a hash -- with the downside that you can only dump actual variables, not the results of anonymous expressions.Give Data::Dump a try if you want something closer to the Data::Dumper experience but with less typing and with cleaner/terser output (and in particular, no silly "
$VAR1 =
" noise in the output).@Matt Perry
Technically, adding the four characters "
2>&1
" to the command-line is less typing overhead than the difference between a single "print Dumper
" vs "p
"... :)Not to mention it adds up if you want to use multiple dump statements in your code.
But you may have a point if you're working in an IDE that makes it annoying to temporarily change the way perl is called for test runs of the script.
Data::Dump doesn't have an equivalent of
local $Data::Dumper::Deparse = 1;
. And the$VAR1 =
crud in Data::Dumper can be suppressed usinglocal $Data::Dumper::Terse = 1;
.Overall, Data::Dump does a better job with whitespace though.
I don't know why bash users still reach for
2>&1
to pipe STDERR. Since version 4 (released five years ago), bash has supported a much simpler syntax borrowed from C shell and Korn shell:This combines STDOUT and STDERR from
command1
and pipes the result intocommand2
. Less typing, and much easier to remember!When your 'finger memory' automatically types '2>&1' then it is just as fast as '|&' :-)
Dude, you should totally learn the Perl debugger.
I'm running OSX 10.8 and I have:
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)
Yowch!
Anyway, the first thing I do on any new Unixy box is:
Hi everyone! I see some of the discussion got a bit sidetracked towards Data::Printer. On this matter, I just wanted to point out that I really appreciate all the enthusiasm and feedback you guys have >shown, and that because it is so hard to please everyone I've built it so you would create a ~/.dataprinter file with your own preferences and never have to worry about it again :)
@tobyink for the issues that you have pointed out, I'd make it like so and never worry about it ever again:
@mattperry for sending the output to stdout you can use a similar .dataprinter file as above, but also adding "output => 'stdout'".
I really wish you guys would give DDP another try and let me know if there is anything I can do in future releases to make it better!
As for Pry, I really liked it, but like Samuel Kaufman said here, I wonder how different it is from Carp::Reply itself. You mentioned it only works when exceptions are thrown, but Carp::Reply let's you put "Carp::Reply::repl();" anywhere in the code and then resume it with Ctrl-D, just like your "pry" command does. Or did I get it wrong?
Toby Inkster:
|& is only inherited from csh, |& in ksh is for co-process creation. So the reason people don't reach for it is perhaps because it is non-standard, non-portable and incompatible. And (luckily) not every /bin/sh is a /bin/bash