Data::Dump::Streamer 1.11 released

demerphq on 2005-05-24T13:00:03

Released the new version of DDS yesterday. Diotalevi from perlmonks worked with me to make it handle a couple of special cases in a much better way.

The main new features are that weakrefs, overloaded objects and closures are all now dumped properly. In particular the lexicals that are bound to a closure a dumped along with it. AFAIK this is the first tool ever to have this feature.

Thanks dio. :-)


Re:

Aristotle on 2005-05-24T23:32:10

So it can serialize closures without losing information?

Re:

demerphq on 2005-05-25T17:02:13

Yep. Eg:

D:\Development>perl -MDDS -e"my $closure=do{ my $x=100; sub { $x++ } }; Dump $closure"

my ($x);
$x = 100;
$CODE1 = sub {
                      $x++;
                  };

I can break this...

btilly on 2005-05-26T01:04:04

The following code crashes.
#! /usr/bin/perl
use strict;
use Data::Dump::Streamer;

Dump [
  map {
    my $x;
    my $x_eclipse_1;
    sub {$x}, sub {$x_eclipse_1};
  } 1, 2
];
I thought about trying to solve this with intelligent mangling, but there is always a boundary case. For instance if you mangle anything with $x_eclipse_1 in some way (eg make it $x__eclipse_1), what if there is a global variable $x_eclipse_1? Now you've changed semantics or else get a crash.

After some thinking, the only strategy that looks like it would work perfectly is to go to a nested data structure in the event of collisions. You could do that like this. Suppose that you had multiple closures pointed at $foo. Then make $foo an anonymous array of scalars and make the closures each point at $foo->[$i] where $i is an index. In the case of @foo you can make it @{$foo[$i]} instead. In the case of %foo you can make it %{$foo{$i}}. In each case the eclipsing is done without accessing any other variable name that might also be accessed.

Re:I can break this...

demerphq on 2005-05-26T05:14:06

The following code crashes.

Shoot. Yep. It does. And it highlights what I forgot to document: the subs being dumped shouldn't mix the use of dynamics and lexicals with the same name, and that its is unwise to use variables matching /_eclipse_\d+$/. (Which personally I think is not such a terrible restriction, albeit not at all ideal.)

Dealing with the former is actually very tricky, and probably wont ever be solved properly. A good example is

my $a=sub { $a++ };

The second issue regarding eclipsed variables is probably easier to solve. For instance I could verify that none of the dumped bound lexicals have a matching name. One approach would be resolving the nesting properly via scoped blocks but there will always be pathological case that can't be reconstructed that way. At that point I'd have to start dealing with aliasing, and frankly I didnt think it was worth it prefering to rename the vars in the subs being dumped.

Unfortunately its not possible to use the strategy you suggested of using an array of "versions" of the var. I actually considered something very similar but it didnt prove to be too promising because of the way Deparse uses names and the options available to me to convince it to use names other than the ones it should. The variable name change logic doesn't involve pattern matching, its done at a lower level by fooling deparse into thinking that the variable names of the vars bound to the sub are different to what they actually are.

Anyway, thanks for the heads up, Ill look into making the eclipsed var name logic smarter to prevent collisions, and ill also add some docs.

I can break this again...

btilly on 2005-05-26T01:16:37

#! /usr/bin/perl
use strict;
use vars '@x_eclipse_1';
use Data::Dump::Streamer;

Dump [
  map {
    my @x;
    sub {$x[0]}, sub {$x_eclipse_1[0]};
  } 1, 2
];
Gets horribly confused.