> Finally, BigInts cannot be serialized to JSON.
Hmm, ok. I guess that's fine. But what about large numbers coming from over the network? Can we get a BigInt-aware JSON.parse() standardized ASAP?
> Finally, BigInts cannot be serialized to JSON.
Hmm, ok. I guess that's fine. But what about large numbers coming from over the network? Can we get a BigInt-aware JSON.parse() standardized ASAP?
JSON is a stable interchange format, and for that reason we’ve got a huge base of tooling that uses and emits it. It’s all interoperable because there is just that one syntax.
So if you say “add JSON.parse() API”, you’re saying “I want to transmit non-Json strings but claim they’re json “.
That breaks:
* old browsers - not supporting bigints would mean they couldn’t parse any of your “json” data, even if you weren’t using the bigints. Eg feature detection wouldn’t work.
* all shipped products that read json, because as with the browsers they could not parse any “json” that contained invalid data.
[edit:
Ok, let's try to do something about the endless downvotes:
Say you do JSON.parse("9007199254740994") - 2^53+2
Should this parse to a BigInt or a Number? In JavaScript today it will parse as a Number, without losing precision, but it is beyond the range of exactly representable integers in JS. You can see this by doing console.log(9007199254740995) and see that the output is 9007199254740996. So what happens if I do that following:
JSON.parse("[9007199254740992, 9007199254740993, 9007199254740994, 9007199254740995]")?
the first and third are exactly representable as a double, the second and forth are not. So should this parse as Number, BigInt, Number, BigInt? Or BigInt, BigInt, BigInt, BigInt? What value should be the trigger for treating an integer as a BigInt vs. a Number? What if we're doing
JSON.parse("[9007199254740992, 9007199254740993, 9007199254740994, 9007199254740995]").map(x=>x+2)
If any of the values get interpreted as a BigInt this will throw. But in existing browsers it won't.
]
And that syntax and specification leaves open the possibility of arbitrary precision integers. From the JSON RFC[1]:
> This specification allows implementations to set limits on the range and precision of numbers accepted.
Those limits vary by implementation. The subsequent paragraphs warn, of course, that not all implementations support sending or receiving numbers outside of certain ranges, and explicitly calls out the contiguous integer range of an IEEE double as a good range for good interoperability.
> “I want to transmit non-Json strings but claim they’re json “.
Those strings are already JSON.
There are serializers out there that support arbitrary precision integers. Python, for example, will happily serialize such integers:
In [6]: json.dumps(2 ** 512)
Out[6]: '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096'
(This will parse in today's browsers, too, but you'll get an imprecise result, as JavaScript's Number cannot represent that value exactly. Larger numbers result in Infinity.)so take:
"[{x:0,y:1},{x:2, y:3456789....}}]"
What should JSON.parse() do? There's no reason for it to parse any of the values before the final extra precision value as a regular number, so if it parses the large one as a bigint, it would break.
> (This will parse in today's browsers, too, but you'll get an imprecise result, as JavaScript's Number cannot represent that value exactly. Larger numbers result in Infinity.)
Your example of python output is exactly the thing that would cause a problem. Your data will work in all existing browsers - it just loses precision. But in any browser that tries to parse it as a bigint it will result in failures, as now any subsequent arithmetic will fail because you can't (for good reasons) mix and match BigInt with non-BigInt values.
You also can't actually make a decision about whether a value should be parsed into a BigInt, vs a Number.
Basically, take something like 2^54 -- 18014398509481984 -- should this be parsed as a Number, or as a BigInt. It's exactly representable with a double, but it has the same value as 2^54+1 (which is not exactly representable). So should that be parsed as a BigInt or as a Number. Without a suffix (not compatible with existing spec) they cannot be distinguished, and so to retain backwards compatibility must be parsed as a Number.
e.g.
JSON.parse(str, null, { useBigint: true});> JSON is agnostic about the semantics of numbers. In any programming language, there can be a variety of number types of various capacities and complements, fixed or floating, binary or decimal. That can make interchange between different programming languages difficult. JSON instead offers only the representation of numbers that humans use: a sequence of digits. All programming languages know how to make sense of digit sequences even if they disagree on internal representations. That is enough to allow interchange
and later more precisely defines a number in a way that does not restrict its maximum size.
> A number is a sequence of decimal digits with no superfluous leading zero. It may have a preceding minus sign (U+002D). It may have a fractional part prefixed by a decimal point (U+002E). It may have an exponent, prefixed by e (U+0065) or E (U+0045) and optionally + (U+002B) or – (U+002D). The digits are the code points U+0030 through U+0039.
http://www.ecma-international.org/publications/files/ECMA-ST...
However changing the behaviour of `JSON.parse` would indeed be a breaking change. That's an issue with the JS spec and web compatibility - not with JSON. The solution there is simple - either make a new function with new rules or add the ability to pass in options to `JSON.parse`.
The "n" notation is just to ensure compatibility within JS - has nothing to do with representing the number in JSON.
JSON numbers are arbitrary precision, how you choose the represent those numbers in your language varies widely, and up to you.
Adding hooks into JSON.parse would actually solve a whole class of problems related to datatype mappings. Right now they're statically defined by whoever implements the parse method but it turns out not to be very flexible.
What if I want to represent my JSON array as an ArrayBuffer or a SortedArray?
What if I want to represent my JSON numbers as strings or my libraries number type for working with currency.
What if I want to map my hashes to my own HashMap?
Being able to say JSON.parse({ array: SortedArray, number: BigInt }) would be very nice.
I need to actually hook into the parser so I can say, "hey when you're about to parse a number pass the token to me and I'll take it from here."
{"value": "90071992547409949007199254740994n"}
Which would get parsed into a BigInt. This specifically means that value isn't a number but a bigint. All JSON consumers that don't support that get strings, all JSON consumers that do get BigInts (when parsing).
The only downside I see is existing json that has strings containing a number and a "n" at the end.
Imagine being on the receiving end of that bug!
{"boring Number not greater than 2^53": 1234}
you could send something like {"exciting huge BigInt": {"value": "12(…)89", "type": "BigInt"}}
where you have all hints what to do with it. You can even invent some funny perks, like {"exciting huge BigInt serialized to base36":
{"value": "12(…)yz", "type": "BigInt", "base": 36}
}
assuming you could create some parseBigInt(radix) function.JSON.stringify(5n) === "5"
JSON.parse("5") === Number(5)
JSON.parse("5000000000000000000") => Error
JSON.parse({ use_bignum: true }) === 5000000000000000000n
A project that does something like this:
JSON.stringify(1n) === "1"
JSON.stringify(100000000000000000000n) === "100000000000000000000"
VM143:1 Uncaught TypeError: Do not know how to serialize a BigInt
at JSON.stringify (<anonymous>)
at <anonymous>:1:17