Search code examples
perleval

Why Dumper output is not evaluated correcty?


I try to eval output of Dumper for pretty simple hashref, where two keys have same value (ref to another hash):

#!/usr/bin/env perl

use strict; use warnings;
use Data::Dumper;

my $foo = { data => 1 };
my $boo = {
  x => $foo,
  y => $foo,
};

my $VAR1;
my $bar = eval( Dumper( $boo ) );

print Dumper( $boo );
print Dumper( $bar ); 

I expect the $boo and $bar to have same structure, but eval seems not solve inner-ref $VAR1->{'x'} correctly, I hoped last 2 lines to print same string:

$VAR1 = {
          'x' => {
                   'data' => 1
                 },
          'y' => $VAR1->{'x'}
        };

But second has x or y undefined (depending which was referenced in literal form):

$VAR1 = {
          'x' => {
                   'data' => 1
                 },
          'y' => undef
        };

I tried simple usage part on doc, and it gave fine results with much more complex structure (no strict, yet), but I can' accomplish it with my data with 2 references to same hash.

What am I missing here?


Solution

  • To correctly capture references inside a structure, you need to set the Purity flag (see the Data::Dumper documentation for details).

    $Data::Dumper::Purity = 1;
    

    It's not enough, though, as Dumper($boo) will now return

    $VAR1 = {
              'y' => {
                       'data' => 1
                     },
              'x' => {}
            };
    $VAR1->{'x'} = $VAR1->{'y'};
    

    So, you can't just eval this string, you also need to return $VAR1 from it.

    To prevent the purity flag interfering with other parts of the code, you can set it locally:

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my $foo = { data => 1 };
    my $boo = {
        x => $foo,
        y => $foo,
    };
    
    my $VAR1;
    my $bar = do {
        local $Data::Dumper::Purity = 1;
        eval Dumper( $boo );
        $VAR1
    };
    
    print Dumper( $boo );
    print Dumper( $bar );