Oh, fun! I didn't know about LVALUE references. For the curious:
perl -E "$str = 'Hi World!'; $sub = \substr $str, 0, 2; $$sub = 'Hello
+'; say $str; say ref $sub"
Hello World!
LVALUE
So the LVALUE is the magic behind how substr works, so that the output can walk and quack like a string scalar, except that changing its value will partially modify the content of another scalar.
Now, there's a simple test to see which of Sereal and Storable does the correct thing. After the data as been serialized and deserialized, it should behave like the original data. For example:
use feature 'say';
use Data::Dump qw( pp );
use Storable qw/ freeze thaw /;
my $array = [0];
push @$array, \$array->[0];
my $copy = thaw freeze $array;
$array->[0]++;
$copy->[0]++;
say "Array:";
say join ", ", map pp($_), @$array;
say pp $array;
say "\nCopy:";
say join ", ", map pp($_), @$copy;
say pp $copy;
__END__
Array:
1, \1
do {
my $a = [1, 'fix'];
$a->[1] = \$a->[0];
$a;
}
Copy:
1, \1
do {
my $a = [1, 'fix'];
$a->[1] = \$a->[0];
$a;
}
So references to elements of a structure should turn into references to the clone element in the clone structure.
Now let's try with substr:
my $struct = ["Hi perlmonks"];
push @$struct, \substr($struct->[0], 0, 2);
my $storable = thaw freeze $struct;
my $sereal = decode_sereal encode_sereal $struct;
pp $struct, $storable, $sereal;
${ $_->[1] } = "Hello", say $_->[0] for $struct, $storable, $sereal;
__END__
Can't handle LVALUE data at C:/Programs/Strawberry/perl/vendor/lib/Dat
+a/Dump.pm line 374.
(
["Hi perlmonks", '#LVALUE#'],
["Hi perlmonks", \undef],
["Hi perlmonks", \"Hi"],
)
Hello perlmonks
Hi perlmonks
Hi perlmonks
So IMHO both
Sereal and
Storable are incorrect, because they should at least warn about LVALUEs not being handled correctly (like
Data::Dump does). In most cases I expect that Sereal is the next best thing though?