Argument passed to Perl VERSION subroutine during module version check - perl

I define a Perl module, like so:
#!/usr/bin/env perl
use strict;
use warnings;
package Sample;
use Data::Dumper;
our $VERSION = v1.10;
sub VERSION
{
my ($class, $version) = #_;
print ("version is $version\n");
print Dumper ($version);
}
The nature of the value passed in $version changes depending on how the module is imported:
$ perl -e 'use Sample 1.0'
version is 1
$VAR1 = '1';
However, if the required module version is specified as a v-string:
$ perl -e 'use Sample v1.0'
version is
$VAR1 = v1.0;
What data type is being passed in $version in the second case? It's apparently not a simple scalar, and it's not a reference.

A v string is a string. Each number is assumed to be a Unicode code point and is converted to that character so what you are actually printing out is chr(1) . chr(0). You can prove this with the following script
my $vstring = v80.101.114.108
print $vstring, "\n";
This will print Perl

Each dot-separated number is converted into a character with the ordinal value of the number.[1] In other words,
v1.0 ≡ "\x01\x00" ≡ chr(1).chr(0) ≡ pack('W*', 1, 0)
You can convert a v-string into something human readable using the %vd format specifier of sprintf.[2]
$ perl -e'CORE::say sprintf("%vd", v1.0)'
1.0
But it's better to use the version module.
$ perl -Mversion -e'CORE::say version->parse(v1.0)'
v1.0
It's better because the version module can handle version strings in general (not just v-strings).
$ perl -Mversion -e'
my $v1 = version->parse(1.0);
my $v2 = version->parse("1.0");
my $v3 = version->parse(v1.0);
my $v4 = version->parse("v1.0");
CORE::say "equal"
if $v1 == $v2
&& $v1 == $v3
&& $v1 == $v4
'
equal
One can use any numerical or string comparison operator[3] to compare version objects.
It's more than that, though. A scalar containing a v-string has magic (of type V) applied, so it's possible to dectect that it's a v-string.
$ perl -MDevel::Peek -e'Dump("\x01\x00"); Dump(v1.0);'
SV = PV(0xbc9d70) at 0xbe7998
REFCNT = 1
FLAGS = (POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0xbf1ed0 "\1\0"\0
CUR = 2
LEN = 10
COW_REFCNT = 0
SV = PVMG(0xc20480) at 0xbe7938
REFCNT = 1
FLAGS = (RMG,POK,IsCOW,READONLY,PROTECT,pPOK)
IV = 0
NV = 0
PV = 0xbf0190 "\1\0"\0
CUR = 2
LEN = 10
COW_REFCNT = 0
MAGIC = 0xbf3a80
MG_VIRTUAL = 0
MG_TYPE = PERL_MAGIC_vstring(V)
MG_LEN = 4
MG_PTR = 0xbf1700 "v1.0"
This magic is even applied to any scalar to which the v-string is copied!
$ perl -MDevel::Peek -e'my $v1 = v1.0; my $v2 = $v1; Dump($v2)'
SV = PVMG(0x9dc500) at 0x9a3a00
REFCNT = 1
FLAGS = (RMG,POK,IsCOW,pPOK)
IV = 0
NV = 0
PV = 0x9ac1b0 "\1\0"\0
CUR = 2
LEN = 10
COW_REFCNT = 2
MAGIC = 0x9b8090
MG_VIRTUAL = 0
MG_TYPE = PERL_MAGIC_vstring(V)
MG_LEN = 4
MG_PTR = 0x9adef0 "v1.0"
I believe the version module takes advantage of this information.
This format specifier works on any string, so it's convenient for checking for hidden or special characters when debugging.
$ perl -e'CORE::say sprintf "%v02X", "abc\r\n"'
61.62.63.0D.0A
==, <, >, <=, >=, <=>, eq, lt, gt, le, ge and cmp.

Related

Difference between $var = 500 and $var = '500'

In Perl, what is the difference between
$status = 500;
and
$status = '500';
Not much. They both assign five hundred to $status. The internal format used will be different initially (IV vs PV,UTF8=0), but that's of no importance to Perl.
However, there are things that behave different based on the choice of storage format even though they shouldn't. Based on the choice of storage format,
JSON decides whether to use quotes or not.
DBI guesses the SQL type it should use for a parameter.
The bitwise operators (&, | and ^) guess whether their operands are strings or not.
open and other file-related builtins encode the file name using UTF-8 or not. (Bug!)
Some mathematical operations return negative zero or not.
As already #ikegami told not much. But remember than here is MUCH difference between
$ perl -E '$v=0500; say $v'
prints 320 (decimal value of 0500 octal number), and
$ perl -E '$v="0500"; say $v'
what prints
0500
and
$ perl -E '$v=0900; say $v'
what dies with error:
Illegal octal digit '9' at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
And
perl -E '$v="0300";say $v+1'
prints
301
but
perl -E '$v="0300";say ++$v'
prints
0301
similar with 0x\d+, e.g:
$v = 0x900;
$v = "0x900";
There is only a difference if you then use $var with one of the few operators that has different flavors when operating on a string or a number:
$string = '500';
$number = 500;
print $string & '000', "\n";
print $number & '000', "\n";
output:
000
0
To provide a bit more context on the "not much" responses, here is a representation of the internal data structures of the two values via the Devel::Peek module:
user#foo ~ $ perl -MDevel::Peek -e 'print Dump 500; print Dump "500"'
SV = IV(0x7f8e8302c280) at 0x7f8e8302c288
REFCNT = 1
FLAGS = (PADTMP,IOK,READONLY,pIOK)
IV = 500
SV = PV(0x7f8e83004e98) at 0x7f8e8302c2d0
REFCNT = 1
FLAGS = (PADTMP,POK,READONLY,pPOK)
PV = 0x7f8e82c1b4e0 "500"\0
CUR = 3
LEN = 16
Here is a dump of Perl doing what you mean:
user#foo ~ $ perl -MDevel::Peek -e 'print Dump ("500" + 1)'
SV = IV(0x7f88b202c268) at 0x7f88b202c270
REFCNT = 1
FLAGS = (PADTMP,IOK,READONLY,pIOK)
IV = 501
The first is a number (the integer between 499 and 501). The second is a string (the characters '5', '0', and '0'). It's not true that there's no difference between them. It's not true that one will be converted immediately to the other. It is true that strings are converted to numbers when necessary, and vice-versa, and the conversion is mostly transparent, but not completely.
The answer When does the difference between a string and a number matter in Perl 5 covers some of the cases where they're not equivalent:
Bitwise operators treat numbers numerically (operating on the bits of the binary representation of each number), but they treat strings character-wise (operating on the bits of each character of each string).
The JSON module will output a string as a string (with quotes) even if it's numeric, but it will output a number as a number.
A very small or very large number might stringify differently than you expect, whereas a string is already a string and doesn't need to be stringified. That is, if $x = 1000000000000000 and $y = "1000000000000000" then $x might stringify to 1e+15. Since using a variable as a hash key is stringifying, that means that $hash{$x} and $hash{$y} may be different hash slots.
The smart-match (~~) and given/when operators treat number arguments differently from numeric strings. Best to avoid those operators anyway.
There are different internally:)
($_ ^ $_) ne '0' ? print "$_ is string\n" : print "$_ is numeric\n" for (500, '500');
output:
500 is numeric
500 is string
I think this perfectly demonstrates what is going on.
$ perl -MDevel::Peek -e 'my ($a, $b) = (500, "500");print Dump $a; print Dump $b; $a.""; $b+0; print Dump $a; print Dump $b'
SV = IV(0x8cca90) at 0x8ccaa0
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 500
SV = PV(0x8acc20) at 0x8ccad0
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x8c5da0 "500"\0
CUR = 3
LEN = 16
SV = PVIV(0x8c0f88) at 0x8ccaa0
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 500
PV = 0x8d3660 "500"\0
CUR = 3
LEN = 16
SV = PVIV(0x8c0fa0) at 0x8ccad0
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 500
PV = 0x8c5da0 "500"\0
CUR = 3
LEN = 16
Each scalar (SV) can have string (PV) and or numeric (IV) representation. Once you use variable with only string representation in any numeric operation and one with only numeric representation in any string operation they have both representations. To be correct, there can be also another number representation, the floating point representation (NV) so there are three possible representation of scalar value.
Many answers already to this question but i'll give it a shot for the confused newbie:
my $foo = 500;
my $bar = '500';
As they are, for practical pourposes they are the "same". The interesting part is when you use operators.
For example:
print $foo + 0;
output: 500
The '+' operator sees a number at its left and a number at its right, both decimals, hence the answer is 500 + 0 => 500
print $bar + 0;
output: 500
Same output, the operator sees a string that looks like a decimal integer at its left, and a zero at its right, hence 500 + 0 => 500
But where are the differences?
It depends on the operator used. Operators decide what's going to happen. For example:
my $foo = '128hello';
print $foo + 0;
output: 128
In this case it behaves like atoi() in C. It takes biggest numeric part starting from the left and uses it as a number. If there are no numbers it uses it as a 0.
How to deal with this in conditionals?
my $foo = '0900';
my $bar = 900;
if( $foo == $bar)
{print "ok!"}
else
{print "not ok!"}
output: ok!
== compares the numerical value in both variables.
if you use warnings it will complain about using == with strings but it will still try to coerce.
my $foo = '0900';
my $bar = 900;
if( $foo eq $bar)
{print "ok!"}
else
{print "not ok!"}
output: not ok!
eq compares strings for equality.
You can try "^" operator.
my $str = '500';
my $num = 500;
if ($num ^ $num)
{
print 'haha\n';
}
if ($str ^ $str)
{
print 'hehe\n';
}
$str ^ $str is different from $num ^ $num so you will get "hehe".
ps, "^" will change the arguments, so you should do
my $temp = $str;
if ($temp ^ $temp )
{
print 'hehe\n';
}
.
I usually use this operator to tell the difference between num and str in perl.

View Perl Variables as Bytes/Bits

Disclaimer: It's been ages since I've done any perl, so if I'm asking/saying something stupid please correct me.
Is it possible to view a byte/bit representation of a perl variable? That is, if I say something like
my $foo = 'a';
I know (think?) the computer sees $foo as something like
0b1100010
Is there a way to get perl to print out the binary representation of a variable?
(Not asking for any practical purpose, just tinkering around with a old friend and trying to understand it more deeply than I did in 1997)
Sure, using unpack:
print unpack "B*", $foo;
Example:
% perl -e 'print unpack "B*", "bar";'
011000100110000101110010
The perldoc pages for pack and perlpacktut give a nice overview about converting between different representations.
The place to start if you want the actual internals is a document called "perlguts". Either perldoc perlguts or read it here: http://perldoc.perl.org/perlguts.html
After seeing the way that Andy interpreted your question, I can follow up by saying that Devel::Peek has a Dump function which can show the internal representation of a variable. It won't take it to the binary level, but if what you are interested in is the internals, you might look at this.
$ perl -MDevel::Peek -e 'my $foo="a";Dump $foo';
SV = PV(0x7fa8a3004e78) at 0x7fa8a3031150
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x7fa8a2c06190 "a"\0
CUR = 1
LEN = 16
$ perl -MDevel::Peek -e 'my %bar=(x=>"y",a=>"b");Dump \%bar'
SV = IV(0x7fbc5182d6e8) at 0x7fbc5182d6f0
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x7fbc51831168
SV = PVHV(0x7fbc5180c268) at 0x7fbc51831168
REFCNT = 2
FLAGS = (PADMY,SHAREKEYS)
ARRAY = 0x7fbc5140f9f0 (0:6, 1:2)
hash quality = 125.0%
KEYS = 2
FILL = 2
MAX = 7
RITER = -1
EITER = 0x0
Elt "a" HASH = 0xca2e9442
SV = PV(0x7fbc51804f78) at 0x7fbc51807340
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x7fbc5140fa60 "b"\0
CUR = 1
LEN = 16
Elt "x" HASH = 0x9303a5e5
SV = PV(0x7fbc51804e78) at 0x7fbc518070d0
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x7fbc514061a0 "y"\0
CUR = 1
LEN = 16
And one more way:
printf "%v08b\n", 'abc';
output:
01100001.01100010.0110001
(The v flag is a perl-only printf/sprintf feature and also works with numeric formats other than b.)
This differs from the unpack suggestion where there are characters greater than "\xff": unpack will only return the 8 low bits (with a warning), printf '%v...' will show all the bits:
$ perl -we'printf "%vX\n", "\cA\13P\x{1337}"'
1.B.50.1337
You can use ord to return the numeric value of a character, and printf with a %b format to display that value in binary.
print "%08b\n”, ord 'a'
output
01100010

Assigning a string to Perl substr?

I am looking at Perl script written by someone else, and I found this:
$num2 = '000000';
substr($num2, length($num2)-length($num), length($num)) = $num;
my $id_string = $text."_".$num2
Forgive me ignorance, but for an untrained Perl programmer the second line looks as if the author is assigning the string $num to the result of the function substr. What does this line exactly do?
Exactly what you think it would do:
$ perldoc -f substr
You can use the substr() function as an lvalue, in which case
EXPR must itself be an lvalue. If you assign something shorter
than LENGTH, the string will shrink, and if you assign
something longer than LENGTH, the string will grow to
accommodate it. To keep the string the same length, you may
need to pad or chop your value using "sprintf".
In Perl, (unlike say, Python, where strings, tuples are not modifiable in-place), strings can be modified in situ. That is what substr is doing here, it is modifying only a part of the string. Instead of this syntax, you can use the more cryptic syntax:
substr($num2, length($num2)-length($num), length($num),$num);
which accomplishes the same thing. You can further stretch it. Imagine you want to replace all instances of foo by bar in a string, but only within the first 50 characters. Perl will let you do it in a one-liner:
substr($target,0,50) =~ s/foo/bar/g;
Great, isn't it?
"Exactly", you ask?
Normally, substr returns a boring string (PV with POK).
$ perl -MDevel::Peek -e'$_="abcd"; Dump("".substr($_, 1, 2));'
SV = PV(0x99f2828) at 0x9a0de38
REFCNT = 1
FLAGS = (PADTMP,POK,pPOK)
PV = 0x9a12510 "bc"\0
CUR = 2
LEN = 12
However, when substr is evaluated where an lvalue (assignable value) is expected, it returns a magical scalar (PVLV with GMG (get magic) and SMG (set magic)).
$ perl -MDevel::Peek -e'$_="abcd"; Dump(substr($_, 1, 2));'
SV = PVLV(0x8941b90) at 0x891f7d0
REFCNT = 1
FLAGS = (TEMP,GMG,SMG)
IV = 0
NV = 0
PV = 0
MAGIC = 0x8944900
MG_VIRTUAL = &PL_vtbl_substr
MG_TYPE = PERL_MAGIC_substr(x)
TYPE = x
TARGOFF = 1
TARGLEN = 2
TARG = 0x8948c18
FLAGS = 0
SV = PV(0x891d798) at 0x8948c18
REFCNT = 2
FLAGS = (POK,pPOK)
PV = 0x89340e0 "abcd"\0
CUR = 4
LEN = 12
This magical scalar holds the parameters passed to susbtr (TARG, TARGOFF and TARGLEN). You can see the scalar pointed by TARG (the original scalar passed to substr) repeated at the end (the SV at 0x8948c18 you see at the bottom).
Any read of this magical scalar results in an associated function to be called instead. Similarly, a write calls a different associated function. These functions cause the selected part of the string passed to substr to be read or modified.
perl -E'
$_ = "abcde";
my $ref = \substr($_, 1, 3); # $$ref is magical
say $$ref; # bcd
$$ref = '123';
say $_; # a123e
'
Looks to me like it's overwriting the last length($num) characters of $num2 with the contents of $num in order to get a '0' filled number.
I imagine most folks would accomplish this same task w/ sprintf()

Devel::Peek Question

% perl -Ilib -MDevel::Peek -le '$a="34567"; $a=~s/...//; Dump($a)'
SV = PV(0x8171048) at 0x8186f48 # replaced "12345" with "34567"
REFCNT = 1
FLAGS = (POK,OOK,pPOK)
OFFSET = 3
PV = 0x8181bdb ( "34\003" . ) "67"\0
CUR = 2
LEN = 9
Where do the 2 zeros in the chomped part ( "12\003" . ) between 2 and 3 come from?
Why do I get this kind of output in the chomped part ( "34\003" . )?
A bug? "\003" is chr(3) in octal form. However:
$ perl -Ilib -MDevel::Peek -le '$a="12345"; $a=~s/...//; Dump($a)'
SV = PVIV(0x869b0bc) at 0x86a5060
REFCNT = 1
FLAGS = (POK,OOK,pPOK)
IV = 3 (OFFSET)
PV = 0x869fac3 ( "123" . ) "45"\0
CUR = 2
LEN = 5
I can't duplicate that; what version of perl are you using?
Note that the part of the string buffer in () is reserved but not currently in use.
I am getting same result as sid_com using perl 5.12.2 on Windows. However the string length is taken from CUR field of structure anyway. I don't see why this should be a bug, there can be any bytes in rest of string buffer.

How does Perl decide to treat a scalar as a string or a number?

Consider the following code and its output:
Code
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;
print Dumper($HOURS_PER_DAY);
print Dumper( $BSA);
print Dumper( $MCG_PER_MG);
print Dumper( $HOURS_DURATION );
Output
$VAR1 = 24;
$VAR1 = '1.7';
$VAR1 = 1000;
$VAR1 = 480;
As you can see, the second variable is treated as strings, while the first and the forth ones are treated as numbers. Anybody has any idea what is the underlying logic?
Edit arithmetic calculations that were added do not completely solve the problem (see the $BSA variable).
$ perl -v
This is perl, v5.10.0 built for cygwin-thread-multi-64int
(with 6 registered patches, see perl -V for more detail)
Copyright 1987-2007, Larry Wall
Data::Dumper's job is to serialize data and you can't tell much about what perl is doing internally with the data based on its output. The Devel::Peek module can dump the underlying flags and values stored in the variables. The Devel::Peek POD explains the significance of the flags.
#!/usr/bin/perl
use warnings;
use strict;
use Devel::Peek;
my $HOURS_PER_DAY = 24.0 * 1.0;
my $BSA = 1.7 * 1.0;
my $MCG_PER_MG = 1000.0 * 1.0;
my $HOURS_DURATION = 20.0 * $HOURS_PER_DAY;
my $dummy = $HOURS_PER_DAY * $BSA * $MCG_PER_MG * $HOURS_DURATION;
Dump($HOURS_PER_DAY);
Dump($BSA);
Dump($MCG_PER_MG);
Dump($HOURS_DURATION);
__END__
SV = PVNV(0xd71ff0) at 0xd87f90
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
IV = 24
NV = 24
PV = 0
SV = PVNV(0xd71fc8) at 0xd87f60
REFCNT = 1
FLAGS = (PADBUSY,PADMY,NOK,pIOK,pNOK)
IV = 1
NV = 1.7
PV = 0
SV = PVNV(0xd72040) at 0xd87f40
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,NOK,pIOK,pNOK)
IV = 1000
NV = 1000
PV = 0
SV = IV(0xd8b408) at 0xd87f30
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 480
# compare the above output to output without the assignment to $dummy:
SV = IV(0x7b0eb8) at 0x7adf90
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 24
SV = NV(0x7c7c90) at 0x7adf60
REFCNT = 1
FLAGS = (PADBUSY,PADMY,NOK,pNOK)
NV = 1.7
SV = IV(0x7b13d8) at 0x7adf40
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 1000
SV = IV(0x7b1408) at 0x7adf30
REFCNT = 1
FLAGS = (PADBUSY,PADMY,IOK,pIOK)
IV = 480
Your whole concept of Perl treating variables as strings or numbers is flawed. Perl will treat your variables the right way when you need it to, for example, arithmetic operators always take treat their argument as numbers (assuming you aren't abusing operator overloading or some such).
You shouldn't worry about this: Perl knows what it's doing.
Data::Dumper is using a simple pattern on the string representation of the variable to determine if it is a number. From the source code:
...
elsif ($val =~ /^(?:0|-?[1-9]\d{0,8})\z/) { # safe decimal number
$out .= $val;
}
else { # string
...
This doesn't match numbers that have a decimal point which explains the behavior you observed.
Quick dirty way to force a numeric context:
print Dumper( $HOURS_DURATION + 0.0 );
If your concern is how the data will be displayed then the clean way is:-
printf "%5.2d",$HOURS_DURATION;