On 6/30/05, Michael G Schwern <[EMAIL PROTECTED]> wrote:
> On Thu, Jun 30, 2005 at 08:03:32AM +0200, demerphq wrote:
> > Yitzchak pointed me to this thread. I thought I'd add that
> > Data::Dump::Streamer v1.14 has the capability to Dump closures
> > properly, that is including bound lexical state.
> 
> Interesting.  is_deeply() can try to use Data::Dumper::Streamer and fall
> back to B::Deparse.  

DDS uses B::Deparse (along with some method overrides) and B::Utils
and basically treats closures as composite objects. So when it
encounters closures it traverse "into" them as well, looking for all
lexicals that are declared outside of the subroutine, which it then
traverses just as it would traverse an AoH or whatever.

Where it gets interesting is that var names can be associated to real
variables in any way when you deal with a closure. This means that $x
in two subroutines may not be the same variable, but $y and $x could
be.

This is an "eclipsed var" scenario, which DDS currently resolves by
_changing_the_name_ of one of the variable to ensure that it is
correctly shared. B::Deparse alone wont do this because it considers
code refs one at a time, and actually doesn't give a toss what storage
is associated to what names.

> Out of curiousity, if Data::Dumper::Streamer can handle
> closures why not fix B::Deparse?

I'm not really sure what you mean by "fix" B::Deparse. B::Deparse does
exactly what it says it does: it deparses code.  We can't consider it
broken for not doing something it doesn't claim to do in the first
place.
 
> 
> > And actually on my first sneaky test of is_deeply it got it wrong.  I
> > actually raised this exact example about is_deeply some years ago.
> > sigh. At least the latest version of Test::More doesnt go into
> > catatonic shock with this test like the one that ships with 5.8.6
> > does.
> 
> Should it not pass?  Each is an array reference with circular $ref->[0] ->
> $ref->[1] -> $ref->[0] scalar references.  There's obviously some sort of
> internal difference but is there a detectable difference at the Perl level?

Yep. Try assigning a value to the deref of the 0 index of $wrap and of
$ar and then dumping again. It makes the difference stand out. The
assignment doesnt change the 1 index of the $wrap array, but it does
change the 1 index of the $ar array.

${$wrap->[0]}=0;
${$ar->[0]}=0;
Dump($wrap,$ar);

__END__
$ARRAY1 = [
            \do { my $v = 0 },
            \do { my $v = 'V: $ARRAY1->[0]' }
          ];
${$ARRAY1->[1]} = $ARRAY1->[0];
$ARRAY2 = [
            'R: $ARRAY2->[1]',
            0
          ];
$ARRAY2->[0] = \$ARRAY2->[1];

the point being that $wrap containas a copy of the references
contained in $x and $y.

Thus $wrap "represents" six items. 1. $wrap the scalar, 2. the array
referenced by $wrap, 3. the scalar in the 0 index of $wrap, 4. the
scalar 1 index of $wrap, 5, the scalar $x, 6. the scalar $y.

Whereas $ar "represents" only four tiems: 1. $ar the scalar, 2. the
array referenced by $ar, 3. the scalar in the 0 index of $ar, 4, the
scalar in the 1 index of $ar.

Incidentally this is a pretty common mistake when handling REF's.
Data::Dumper does it as does YAML and pretty much all the other
storage tools that i have looked at, although Storable gets it right.
Also, i should say that while this circular ref stuff does look
bizarre it really is just a simple example of a general class of
datastructure that many dumpers get wrong.

-- 
perl -Mre=debug -e "/just|another|perl|hacker/"

Reply via email to