Domanda

I made this script to check how scalars change when accidently using 'eq' instead of '==' and vice versa. Using '==' on strings changes nothing but using 'eq' on numbers makes the scalar change somehow. Here comes the code:

#!/usr/bin/perl
use strict;
use JSON;

my $str = "123";
my $num = 123;

print "BEFORE:\n";
print "str: ", \$str, " num: ", \$num, "\n";
print to_json({str => $str, num => $num}, {pretty => 1});

if ($str == 23) { }
if ($num eq "123") { }

print "AFTER:\n";
print "str: ", \$str, " num: ", \$num, "\n";
print to_json({str => $str, num => $num}, {pretty => 1});

print "\n";

Output:

BEFORE:
str: SCALAR(0x8010f8) num: SCALAR(0x801050)
{
      "num" : 123,
      "str" : "123"
}
AFTER:
str: SCALAR(0x8010f8) num: SCALAR(0x801050)
{
      "num" : "123",
      "str" : "123"
}

With words, $num is changed from being a number to being a string. By commenting the line

if ($num eq "123") { }

$num is not changed anymore. Is this a bug or feature? Why does this happen? Also, how can I see this without using to_json?

perl --version
This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi
È stato utile?

Soluzione

Perl variables are multivalued, e.g. they have slots for string, integer, floating point and reference.

If you assign a string to a variable it will be stored in the string slot and this slot will be marked as valid. If you later access the variable as a number, the string will be converted and the floating point or the integer slots will be updated and marked valid. In your example $str will initially have a valid string slot and after the comparison with an integer it will also have valid integer slot. If you would have compared it with a float it would have a valid float slot instead. You might check this with Devel::Peek::Dump: POK means valid string slot, IOK is a valid integer slot and NOK a valid float slot.

Similar things happen, if you store an integer and later use it as a string. In your example $num will have initially a valid integer slot (IOK) and once you access it as a string (by using eq) it will be converted to a string and the string slot will be filled and be valid (POK) additionally to the integer slot.

to_json probably just looks at the variable and takes the first valid slot it finds, starting with the string (I guess this must be encode_sv in JSON::XS - this checks in this order: string, float, integer). So if the string slot is valid it will be printed with quotes around it.

Other languages (like python) don't have this multi-slot thing, they just have a single type and if you use the variable in another context it will croak. Both ways have their pros and cons :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top