Live data from Hacker News

Unintuitive JSON Parsing

nullprogram.com

61–70 of 77 posts

Re: Unintuitive JSON Parsing

#61
post #25

Earlier quoted context omitted.

Yep. It's technically incorrect. It seems honoring this type of technical correctness matters a lot. For example, imagine if ECMA added a new feature (e.g. 0-prefixed octal literals) in 2020.. Another issue: security. Imagine a hacker figured out that you used a mix of JSON parsers on your application (e.g. V8 and jq), and they produced different output. For a vaguely related example, consider that some URL parsers i…

I believe what you're actually saying is that regardless of whether or not it is technically correct, it would be incorrect (and I agree with you there). My question was more "for inputs not defined as being valid by the spec, is the result undefined (a la C++ UB where anything and everything is legal in response) or is it required to reject said input". The sibling response says extensions are allowed, but that woul…

Section 9 of the RFC would indeed technically allow interpreting 01 as you please, but section 6 states:

“Numeric values that cannot be represented in the grammar below... are not permitted”

Regardless I agree we should not do such things.

Re: Unintuitive JSON Parsing

#62
post #33

Earlier quoted context omitted.

That said, in theory, shouldn't: JSON.parse("0o10") === 8? I get SyntaxError: Unexpected token o in JSON at position 1

No. Valid json is valid JavaScript. Valid JavaScript is not, necessarily, valid json.

Thanks, I misunderstood the proposal, which apparently applies mostly to "unescaped LINE SEPARATOR or PARAGRAPH SEPARATOR characters" within strings.

Re: Unintuitive JSON Parsing

#63

I think JSON would be vastly improved if it were to just allow comments. Maintaining configuration in JSON is unnecessarily painful due to this pointless feature gap.

It wasn't an arbitrary decision, there's a hard reason: round-trip format conversion.

https://en.wikipedia.org/wiki/Round-trip_format_conversion

The reason JSON can't support comments the way XML does, is that comments aren't part of the JavaScript "DOM". They disappear when you parse them, so they can't round-trip, and there's now way to stringify comments back out.

Standard XML parsers and XML/HTML DOM APIs give you all the comments and whitespace, and it's up to you to ignore them if you don't care, and they're not lost when you parse and re-serialize. Comments and whitespace are part of the standard DOM/SAX API, but you can't just nail those onto another model like JavaScript polymorphic objects/arrays after the fact.

Because parsed JavaScript objects and JSON structures provide no way to access the comments the parser threw away.

Although of course you could implement a parser that saved the comments, but it would need to support another more complex API than directly accessing JSON objects, which could somehow describe where each comment was in relation to the parsed object (since multiple comments can appear anywhere), and what kind of comment it was (// or /* */), as well as where all the whitespace the parser ignored was. (Although XML parsers typically don't tell you about whitespace inside of tags, so that can't round-trip.)

That is theoretically feasible with a JSON API implemented from the ground up in any language, like JSON.Net for example. But it's not practical in JavaScript itself (or Python or any language that parses JSON into pre-existing polymorphic arrays and objects), because you parse JSON into actual JavaScript (or Python) objects, whose API and implementation isn't under your control. So JSON being able to round-trip with any language other than JavaScript (and Python) itself would have been silly.

JSON would not be as powerful and useful a format if parsing then serializing JSON lost information. JSON was meant to be a round-trippable format, so there was no other choice but to leave out comments.

But maybe there's a use case for a "lossy" compressed JSON format like JPEGSON. ;)

https://en.wikipedia.org/wiki/Lossy_data_conversion

Re: Unintuitive JSON Parsing

#64

Earlier quoted context omitted.

If you have a file or network stream with millions of separate JSON items, then you might want to parse and process each item separately as it is received, and the surrounding structure just gets in the way. That being said, it's properly better to explicitly acknowledge that you're using something-like-json-but-not-really-json like http://jsonlines.org does instead of simply concatenating json objects.

With the application understanding that the top level object is an array of independently parsable json objects, it should still be possible to stream the format I suggested, assuming you use a streaming / sax parser.

Streaming parsers are very inconvenient to work with.

Re: Unintuitive JSON Parsing

#65
post #30

Earlier quoted context omitted.

JSON was made to be "based on a subset" of Javascript. The only way to be compatible with JS while removing octals is to disallow leading zeroes entirely. Doing otherwise would lead to JSON and JS behaving differently with the same input. Of course, until recently JSON wasn't a strict subset of JS but that was an oversight rather than by design.

I've been programming for 30 years, across many different languages from assembler and up. I've yet to use octals for any code. What am I missing out on? Why are they included in modern languages like JS?

If you ever want to count in base-8 (or a subset), or have an abbreviated form of binary, or pack decimal in a way that's easier to reason, or divide a number in half (down to 1) without getting fractions, or represent file permissions (a grouping of four octals).

Is JS a modern language? It was made 24 years ago as a prototype for a scripting language loosely mimicing Java. Presumably octals would have been still used often on recent machines.

Re: Unintuitive JSON Parsing

#66

> The parser will not complain about leading zeros because JSON has no concept of leading zeros. Of course there is no logical reason why the parser shouldn't have this concept just because the spec doesn't require. IMO, beyond basic correctness, user friendly error messages are the main differentiator between excellent parsers and crappy parsers.

When your inputs are from real JSON emitters, it is silly to even have error handling other than rejection. Helpful error messages for humans writing JSON is a special use case, not "the main differentiator" marking an "excellent [parser]". Exposing a "helpful" JSON parser to the internet is a bad idea, and probably a waste of electricity, since the error messages will likely go into a black hole. An "excellent" pars…

> When your inputs are from real JSON emitters, it is silly to even have error handling other than rejection.

I'm guessing from this that a "real JSON emitter" is one that perfectly implements the JSON spec and has absolutely zero bugs? Does such a thing exist?

> Exposing a "helpful" JSON parser to the internet is a bad idea, and probably a waste of electricity, since the error messages will likely go into a black hole.

There's a lot of software where any kind of unexpected error just gets repeated back to the user. I'm sure you've seen a modal popup like:

    Unexpected error, please try again 
    (SyntaxError: JSON.parse: expected ‘,’ or ‘]’ after array element)
This is immensely unhelpful to basically everyone involved. If the message at least hints that it's due to a problem with the input itself -- for example: "SyntaxError: Invalid value ‘01’" -- then it's much more likely that an end-user can figure out which value is causing the problem and work-around it, and report a much more meaningful bug to the developer (thus allowing it to be solved significantly faster).

Taking the argument that "helpful" JSON parse errors are pointless to its logical conclusion, there should only be a single possible error "JSON parsing failed", and I can't see how that's anything but a recipe for making everyone absolutely despise your API/product/etc, especially were your JSON parser ever to have even a single bug that caused that response erroneously.

Re: Unintuitive JSON Parsing

#67
The problem with octal formatted numbers, and why JSON (and strict mode JS) explicitly disallow them dates back to the JS engines of the time.

Essentially you have Netscape and IE. Netscape added support for "octal", IE did not, that meant that you had code like `x = 017` that had different values in the two engines. Given the early JSON parsers essentially just called eval() on the string that wasn't ok behavior for a data interchange format.

Then you have the absurd behavior of the Netscape octal implementation, which leads to such wonders as `018-017==3`, which make it a super terrible footgun.

Sensibly modern syntax makes the difference between octal and decimal very explicit with a 0o prefix, just like 0x, 0b, etc. I wish I knew why it was originally decided to not use 0o when 0x was in use.

Re: Unintuitive JSON Parsing

#68
post #4

> The parser will not complain about leading zeros because JSON has no concept of leading zeros. Of course there is no logical reason why the parser shouldn't have this concept just because the spec doesn't require. IMO, beyond basic correctness, user friendly error messages are the main differentiator between excellent parsers and crappy parsers.

Reporting the last valid input and the start of the first invalid location (possibly repeating the first couple characters of invalid content, filtered for safety) is what I'd generally prefer in an error message.

Showing the boundary between accepted and rejected input is indeed a good idea.

The case discussed in the article would benefit of a display with spaces between tokens.

Example: Source: [01] Compiler error: [ 0 1 ] ----^ SyntaxError: JSON.parse: expected ‘,’ or ‘]’ after array element

Such situation of two tokens without a separator character becomes much more obvious.

Notice also the character showing point of error. OCaml has been doing for a while ( https://ocaml.org/learn/tutorials/common_error_messages.html now shows underlined parts) then clang, cf. https://clang.llvm.org/diagnostics.html . This is much quicker for the human to communicate, than "line x column y".

Re: Unintuitive JSON Parsing

#69
post #7

I was initially surprised that all the lexers treat "[01]" as four tokens, but it makes sense from the state diagram. In the past I've encountered JSON lexing that only considers token boundaries on "special" characters i.e. ",}]:" and whitespace. This will return a lexing error when it sees "01" (equivalently "truefalse").

You're right. Current parser violates the https://en.m.wikipedia.org/wiki/Principle_of_least_astonishm... when it breaks a string of characters without a whitespace into several tokens.

One could imagine first tokenizing only based on whitespace, then only starting to figure out what the tokens are. Which means parsing them individually. Which means another parsing step.

I think this would match human more closely: structure is more obvious based on visual separation than detailed analysis.

I guess it wasn't done that way because the current way of operation means one parser to rule all sources, and that parser can handle more complicated cases. That kind of design decision is more surprising later, but is kind of understandable when you draft a language as the same time as your first parser.

Re: Unintuitive JSON Parsing

#70

Why is concatenated json a thing? In what sense is: {0}{1} better than [{0},{1}]? Presumably, if a few bytes are a major concern, you aren't using JSON anyway.

If you have a file or network stream with millions of separate JSON items, then you might want to parse and process each item separately as it is received, and the surrounding structure just gets in the way. That being said, it's properly better to explicitly acknowledge that you're using something-like-json-but-not-really-json like http://jsonlines.org does instead of simply concatenating json objects.

The delimiters don't get in the way, they protect you from MITM and other attacks. It's a security feature, not a bug.
Post reply on HN