-
Notifications
You must be signed in to change notification settings - Fork 40
Description
JSON exports a decode_json that it chooses from either the preferred installed JSON parser or an acceptable one that the user provides. However, decode_json from JSON::XS and JSON::PP act slightly differently.
The first question is how JSON might want to handle this. Reading through previous bug reports, I've seen that JSON might not want to track divergent interfaces.
I'd think that the most user-friendly solution is to make decode_json act the same way despite the backend. On the development side that's a bit hairy.
The problem
In I don't want no 'wantarray', Juho Snellman notes that if decode_json uses a function call as its argument, the backend matters because JSON::XS and JSON::PP use different contexts for their argument list. JSON::XS uses scalar context but JSON::PP uses list context. Unfortunately, he used File::Slurp::read_file and was bit by its context-sensitive return value:
#!/usr/bin/perl
use v5.26;
use JSON::XS ();
use JSON::PP ();
say "JSON::XS " . JSON::XS->VERSION . " ------------";
my $ds_xs = eval { JSON::XS::decode_json read_file() };
say "Error: $@\n" if $@;
say "JSON::PP " . JSON::PP->VERSION . " ------------";
my $ds_pp = eval { JSON::PP::decode_json read_file() };
say "Error: $@\n" if $@;
say "done";
sub read_file {
my $json = <<~"JSON";
{
"camel": "Amelia"
}
JSON
say "Wantarray is <" . wantarray . ">";
wantarray ? split(/\R/, $json) : $json;
}
The result shows that JSON::PP only gets the first line of the JSON becuase it was called in list context:
$ perl json.pl
JSON::XS 4.03 ------------
Wantarray is <>
JSON::PP 4.07 ------------
Wantarray is <1>
Error: , or } expected while parsing object/hash, at character offset 1 (before "(end of string)") at json.pl line 12.
done
This shows up on which one JSON loads
#!/usr/bin/perl
use v5.26;
BEGIN {
$ENV{PERL_JSON_BACKEND} = $ARGV[0] // 'JSON::XS';
}
use JSON;
say "JSON backend is ", JSON->backend;
my $ds = decode_json read_file();
sub read_file {
my $json = <<~"JSON";
{
"camel": "Amelia"
}
JSON
say "Wantarray is <" . wantarray . ">";
wantarray ? split(/\R/, $json) : $json;
}
If the backend is not JSON::PP (and acceptable to JSON), there's no problem:
$ perl json2.pl
JSON backend is JSON::Backend::XS
Wantarray is <>
$ perl json2.pl JSON::PP
JSON backend is JSON::Backend::PP
Wantarray is <1>
, or } expected while parsing object/hash, at character offset 1 (before "(end of string)") at json2.pl line 12.
$ perl json2.pl Cpanel::JSON::XS
JSON backend is JSON::Backend::XS
Wantarray is <>
$ perl json2.pl Foo
The value of environmental variable 'PERL_JSON_BACKEND' is invalid. at json2.pl line 8.
Compilation failed in require at json2.pl line 8.
BEGIN failed--compilation aborted at json2.pl line 8.