Wakan Tanka
Wakan Tanka

Reputation: 8042

Making more of Perl Data::Dumper output

I have several nested data structures that refer to one another's elements. I would like to be able to check those references, so I am searching for something that will print the memory address of nested structures. An option for Data::Dumper would be fine.

Here are some examples of what I mean:

my @a = ( [1,2,3], [4,5,6] );
print \@a;

Will give you something like:

ARRAY(0x20071dc8)

When you run the same code through the debugger and examine the array with x \@a it will print this:

0  ARRAY(0x20070668)
   0  ARRAY(0x2006c0d8)
      0  1
      1  2
      2  3
   1  ARRAY(0x2006c1b0)
      0  4
      1  5
      2  6

But using Data::Dumper

print Dumper \@a;

It looks like this

$VAR1 = [
          [
            1,
            2,
            3
          ],
          [
            4,
            5,
            6
          ]
        ];

What I really want is a mixture of the Data::Dumper output and the details that the debugger provides. Perhaps this

$VAR1 = [ ARRAY(0x20070668)
          [ ARRAY(0x2006c0d8)
            1,
            2,
            3
          ],
          [ ARRAY(0x2006c1b0)
            4,
            5,
            6
          ]
        ];

Edit

Consider this code. The output doesn't explain that $b[1] is the same reference as in $a[0]

use Data::Dumper;

my @a = ( [1,2,3], [4,5,6] );
my @b = ( ["a","b","c"], $a[0] );

print Dumper \@b

print $b[1], "\n";
print $a[0], "\n";

output

$VAR1 = [
          [
            'a',
            'b',
            'c'
          ],
          [
            1,
            2,
            3
          ]
        ];


ARRAY(0x2002bcc0)
ARRAY(0x2002bcc0)

Also, is this approach, when one structure references the contents of another, considered to be good programming practice? Maybe this is too general question and heavily depends on particular code but I would like to know your opinion.

Upvotes: 1

Views: 868

Answers (2)

Borodin
Borodin

Reputation: 126722

I believe that far too little attention is paid to Data::Dump. It is written by Gisle Aas, the author of the remarkable LWP suite of modules.

It will help you in this case because there is a companion Data::Dump::Filtered module that allows you to supply a callback to dictate exactly how each item should be displayed in the dump.

This program takes the data in your question as an example. It employs a callback that adds the stringified version of the reference as a Perl comment before each array is displayed. The dump is very similar to your requirement, and as a bonus it is still valid Perl code that can be passed through eval if necessary.

Note that all dump output is sent to STDERR so I have called select STDERR to keep the print output in synch with the dumps.

use strict;
use warnings;

use Data::Dump::Filtered qw/ dump_filtered /;

my @a = ( [1,2,3], [4,5,6] );
my @b = ( [ qw/ a b c / ], $a[0] );

select STDERR;

dump_filtered(\@a, \&filter);
print "\n";

dump_filtered(\@b, \&filter);
print "\n";

print '$b[1] is ', $b[1], "\n";
print '$a[0] is ', $a[0], "\n";

sub filter {
  my ($thing, $ref) = @_;
  return { comment => "$ref" } if $thing->is_array;
}

output

# ARRAY(0x45179c)
[
  # ARRAY(0xa2d36c)
  [1, 2, 3],
  # ARRAY(0x44adc4)
  [4, 5, 6],
]

# ARRAY(0x4e6964)
[
  # ARRAY(0xa2d534)
  ["a", "b", "c"],
  # ARRAY(0xa2d36c)
  [1, 2, 3],
]

$b[1] is ARRAY(0xa2d36c)
$a[0] is ARRAY(0xa2d36c)

Upvotes: 4

Miller
Miller

Reputation: 35198

Data::Dumper will already tell if a reference is reused.

In the following example, the 2nd and 3rd elements of the AoA are identical. This is represented in the Dumper output:

use strict;
use warnings;

my @array1 = (1..3);
my @array2 = (4..6);

my @AoA = (\@array1, \@array2, \@array2);

use Data::Dumper;
print Dumper \@AoA;

Outputs:

$VAR1 = [
          [
            1,
            2,
            3
          ],
          [
            4,
            5,
            6
          ],
          $VAR1->[1]
        ];

Responding to your edit

If you want to find the relation between two different data structures, just make a single call to Dumper with both data structures.

You can do this by passing them as a list, or as values in another anonymous data structure, like a hash or array:

use strict;
use warnings;

my @a = ([1,2,3], [4,5,6]);
my @b = (["a","b","c"], $a[0]);

use Data::Dumper;

print Dumper(\@a, \@b);

Outputs:

$VAR1 = [
          [
            1,
            2,
            3
          ],
          [
            4,
            5,
            6
          ]
        ];
$VAR2 = [
          [
            'a',
            'b',
            'c'
          ],
          $VAR1->[0]
        ];

Upvotes: 4

Related Questions