The genesis and usage of Data::Dumper::Concise and Devel::Dwarn

Sat Feb 13 22:30:00 2010

Digg! submit to reddit Delicious RSS Feed Readers

There are two main schools of debugging in my experience - "give me an interactive debugger and let me play" and "you can have printf when you pry it from my cold, dead fingers". Smalltalk people are almost always of the first class since they have a better debugger than, well, everybody; I am, I suppose inevitably given my tendencies towards minimalist development toolsets, very definitely of the second.

Now, the most common tool for doing this with perl is Data::Dumper, which allows you to simply write:

  use Data::Dumper;
  print Dumper($var);

However, the default output leaves a little to be desired - it sticks '$VAR1 =' on the front and indents things massively and produces hash keys in random order.

Fortunately, you can configure Data::Dumper, either by creating an object or by setting package variables:

  my $dd = Data::Dumper->new([])
                       ->Sortkeys(1);

  $Data::Dumper::Sortkeys = 1;

However, the former gets kind of long winded, and the latter is nastily global. Of course, you can turn it on only for the currently executing code by using:

  {
    local $Data::Dumper::Sortkeys = 1;
    ... # code that uses Dumper goes here
  }

This doesn't help with the fact that there's quite a few options you usually set though, and it doesn't help the fact you find yourself copypasting or recreating the option set every time you touch a new piece of code. So having got bored of this, I wrote up Data::Dumper::Concise::Sugar so that:

  use Data::Dumper::Concise;

  warn Dumper($var);

is equivalent to:

  use Data::Dumper;
  {
    local $Data::Dumper::Terse = 1;
    local $Data::Dumper::Indent = 1;
    local $Data::Dumper::Useqq = 1;
    local $Data::Dumper::Deparse = 1;
    local $Data::Dumper::Quotekeys = 0;
    local $Data::Dumper::Sortkeys = 1;
    warn Dumper($var);
  }

This simplifies things quite a bit - and for added bonus points, with an empty argument list we return the dumper object for you to use:

  my $dd = Dumper;

This made life substantially nicer - DBIx::Class now uses it to format debug output by default, since it turned out my usual options were a subset of what the DBIC code had ended up with and I was able to merge them. Unfortunately, having this available made me far more conscious of the other faffing I had to do when adding debug logging - notably, changing:

  return ($foo, $bar, $baz);

to

  my @ret = ($foo, $baz, $baz);
  return @ret;

all the time started to be excessively annoying. And so was born Data::Dumper::Concise::Sugar which provides two functions, Dwarn and DwarnS, that warn+Dumper's their arguments and then return them - the former operating in list context and the latter in scalar. That allows you to write:

  return Dwarn ($foo, $baz, $baz);

  return DwarnS $x;

and get suitable results. We even added a shorter alias for it, Devel::Dwarn to save typing when adding it to test code.

When using it in the middle of method chains, I found myself writing:

  $obj->foo
      ->bar
      ->${\sub { DwarnS $_[0] }}
      ->baz

which while working isn't brilliantly legible or particularly easy to type - so we made Devel::Dwarn import Data::Dumper::Concise::Sugar into itself as well as providing the exports, which means you can now write:

  $obj->foo
      ->bar
      ->Devel::Dwarn::Dwarn
      ->baz

which is rather clearer, on the whole.

This post documents the features as of version 1.200 - if you get a subsequent release do check the Changes file since we're planning on adding a few more convenience features over time once we've played with them thoroughly in our own code.

Thanks to Frew Schmidt (frew), fellow Iron Man contender and DBIx::Class developer, for contributing docs, ideas and tests. Come bug us on #dbix-class on irc.perl.org if you'd like to join in - the source is available via git.shadowcat.co.uk and at git://git.shadowcat.co.uk/p5sagit/Data-Dumper-Concise.git for clone.

Happy debugging!

-- mst, out.