Strings and numbers in Perl are represented by the same data type: scalars. When the JSON module encounters something that looks like a number, it has to guess whether you wanted to output it as a number or a string. To do this it peeks at the scalar's internals (the SV structure - in particular, its flags) to see whether the scalar has ever been treated as a string. If it has, then it outputs it as a quoted string.
Install Devel::Peek and note the difference here:
$ perl -MDevel::Peek -E'my $x = 1; print "$x\n"; print Dump($x)'
1
SV = PVIV(0x864e218) at 0x864d738
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 1
PV = 0x86483a8 "1"\0
CUR = 1
LEN = 12
$ perl -MDevel::Peek -E'my $x = 1; print $x,"\n"; print Dump($x)'
1
SV = IV(0x86b0724) at 0x86b0728
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 1
In the first example, the variable $x has been interpolated into a string, and thus acquires a POK flag indicating that the SV structure has a pointer to a string. In the second example, although $x has still been printed out, with a new line afterwards, there was no concatenation; no string operator performed on $x; so it doesn't acquire a POK flag. The JSON module would output this as a number.
You can make a variable's POK flag disappear by adding 0 to it:
$ perl -MDevel::Peek -E'my $x = 1; print "$x\n"; $x += 0 ;print Dump($
+x)'
1
SV = PVIV(0x9cba210) at 0x9cb9730
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 1
PV = 0x9cb43a0 "1"\0
CUR = 1
LEN = 12
Notice that the actual string pointer has been kept (that's the PV line), but it is no longer "OK" - it might have been invalidated by the addition, so the POK flag has gone.
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
|