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/"