Why is version-> parse not working without previous printing?

I must admit that this one was jubilant.

Consider this code:

use version; use Data::Dumper; my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)}; print STDERR qq{$codeLevel\n}; my $vrmf; if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) { print STDERR "$1\n"; $vrmf = version->parse($1); } print STDERR Dumper($vrmf); 

The conclusion, as expected, is as follows:

 6.1.0.7 (build 25.3.1103030000) 6.1.0.7 $VAR1 = bless( { 'original' => '6.1.0.7', 'qv' => 1, 'version' => [ 6, 1, 0, 7 ] }, 'version' ); 

However, remove the second seal:

 use version; use Data::Dumper; my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)}; print STDERR qq{$codeLevel\n}; my $vrmf; if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) { $vrmf = version->parse($1); } print STDERR Dumper($vrmf); 

The output will be:

 6.1.0.7 (build 25.3.1103030000) $VAR1 = bless( { 'original' => '0', 'version' => [ 0 ] }, 'version' ); 

I cannot find documentation that says print can affect variables passed to it or affect variables matching regular expressions.

Can someone explain to me what is going on here, please?

+4
source share
5 answers

Scalar values ​​in Perl can be a number and a string at the same time. An SV object (SV = Scalar Value) has slots for integer, floating, and string values ​​and flags that determine which of these values ​​are valid at any given time. When you use a string value, perl evaluates the string value and sets a flag that identifies it as valid. (Other operations, such as appending 1, invalidate the string value.) When you print something that you (not surprisingly) use as a string. You can see this with Devel :: Peek.

 use Devel::Peek; my $s = '6.1.0.7 (build 25.3.1103030000)'; if ($s =~ /^\s*([0-9.]*) \(build.*\)/) { Dump($1); printf STDERR "\$1 = $1\n"; Dump($1); } 

Result

 SV = PVMG(0x1434ca4) at 0x144d83c REFCNT = 1 FLAGS = (GMG,SMG) IV = 0 NV = 0 PV = 0 MAGIC = 0x146c324 MG_VIRTUAL = &PL_vtbl_sv MG_TYPE = PERL_MAGIC_sv(\0) MG_OBJ = 0x144d82c MG_LEN = 1 MG_PTR = 0x14631c4 "1" $1 = 6.1.0.7 SV = PVMG(0x1434ca4) at 0x144d83c REFCNT = 1 FLAGS = (GMG,SMG,pPOK) IV = 0 NV = 0 PV = 0x1487a1c "6.1.0.7"\0 CUR = 7 LEN = 8 MAGIC = 0x146c324 MG_VIRTUAL = &PL_vtbl_sv MG_TYPE = PERL_MAGIC_sv(\0) MG_OBJ = 0x144d82c MG_LEN = 1 MG_PTR = 0x14631c4 "1" 

Notice that in the second output of the dump, the PV slot (string value) was filled and the pPOK flag was added to FLAGS.

So yes, print has side effects, although under normal circumstances you will never notice. version->parse() seems to expect a string argument, but does not invoke string semantics. Given that version prefers to use the XS implementation, this is probably a bug, not perl. Note that making a copy of the capture data causes the problem to disappear:

 use Data::Dump qw'pp'; my $s = '6.1.0.7 (build 25.3.1103030000)'; if ($s =~ /^\s*([0-9.]*) \(build.*\)/) { my $x = $1; pp(version->parse($x)); } 

Result:

 bless({ original => "6.1.0.7", qv => 1, version => [6, 1, 0, 7] }, "version") 
+5
source

It looks like an error in the :: parse version that it does not start magic correctly according to the incoming parameter.

A look at the code reveals the same problem in CPAN and major "versions"; he checks SvOK long before he turns to magic. Unfortunately, this will be due to a fix both in the module code and in the perl core.

+4
source

This is reproduced from Perl 5.14.1 on MacOS X 10.6.8 using the XS implementation of "version" 0.91 (version version 0.91) ...

However, this is a mistake in the implementation of version::vxs (XS implementation), and not in the version::vpp (pure Perl).

 use version::vxs; use Data::Dumper; my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)}; print STDERR qq{$codeLevel\n}; my $vrmf; if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) { $vrmf = version::vxs->parse($1); } print STDERR Dumper($vrmf); 

This is not how you showed. When I compiled a clean version of Perl ( perl Makefile.PL --perl_only , as mentioned in the README file) and tested it, it worked correctly:

 $ perl -Iblib/lib x4.pl 6.1.0.7 (build 25.3.1103030000) $VAR1 = bless( { 'original' => '6.1.0.7', 'qv' => 1, 'version' => [ 6, 1, 0, 7 ] }, 'version::vpp' ); $ cat x4.pl use version::vpp; use Data::Dumper; my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)}; print STDERR qq{$codeLevel\n}; my $vrmf; if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) { $vrmf = version::vpp->parse($1); } print STDERR Dumper($vrmf); $ 

I think you could reasonably report this to CPAN RT (author of JPEACOCK). As a workaround, manually install a clean version of Perl and uninstall the XS version (since the code first looks for XS code - see version-0.91/lib/version.pm ). If you are really brave, think about what the real mistake is.

+3
source

Is this not always the case; you ask a question, and then find the answer!

This code:

 use version; use Data::Dumper; my $codeLevel = q{6.1.0.7 (build 25.3.1103030000)}; print STDERR qq{$codeLevel\n}; my $vrmf; if($codeLevel =~ /^\s*([0-9.]*) \(build.*\)/) { $vrmf = version->parse("$1"); } print STDERR Dumper($vrmf); 

Works correctly. Please note that here $ 1 has been pinned.

However, this leaves an interesting point: printing this variable seems to reinforce it for a long time!

0
source

I don’t know the special magic behind version numbers, but with overload you can give almost any side effect you want to stitch.

 package My::Class; use overload '""' => \&arbitrary_function; ... $obj = My::Class->new(); print $obj; # invokes &arbitrary_function 
0
source

All Articles