Search code examples
perl

Why do I have to use an intermediate variable in Perl when JSON-decoding a file with newlines?


I'm using the read_file sub from the File::Slurp module and the decode_json sub from the JSON module to easily read the contents of a file for JSON decoding. However, I found that when my file contains newlines, I can't directly pass the return value of read_file to decode_json, as I receive an error regarding invalid JSON. Instead, I have to store the return value of read_file into a variable before passing it.

I'm still pretty new to Perl (using v5.30 or v5.38 depending on system), and coming from languages like JS and Python this surprises me; why is this intermediate variable assignment required? Not that this isn't an easy enough workaround, just looking to satisfy my curiosity.

Example:

use v5.38;
use warnings;
use strict;

use File::Slurp qw( read_file );
use JSON        qw( decode_json );

my $contents = read_file('test.json');
my $decoded  = decode_json($contents);
say "Decoded contents";

my $chained_decoded = decode_json( read_file('test.json') );
say "Decoded chained contents";

Alongside a file test.json with the contents:

[{ "a": "b" }, { "b": "c" }]

This causes no errors, and both logs show up.

However, with the contents:

[
    { "a": "b" },
    { "b": "c" }
]

I see the first log, but then the error , or ] expected while parsing array, at character offset 2 (before "(end of string)") at test.pl line 12. is thrown


Solution

  • read_file is documented as being context-sensitive: in scalar context it returns the entire contents of the file as one string. In list context it returns a list of lines.

    The arguments list of a function call is a list context, but decode_json doesn't want a list of lines, it wants the whole file in the first argument and ignores the rest.

    You can force scalar context by writing decode_json(scalar read_file('test.json')).