json5 / json5-spec

The JSON5 Data Interchange Format
https://spec.json5.org
MIT License
49 stars 11 forks source link

Recommend support for BigInt #36

Open apprat opened 2 years ago

apprat commented 2 years ago

const object = {id: 123n} stringify can be stored as {"id": 123n} Can be correctly converted to bigint instead of number during parse

apprat commented 2 years ago

In my current software, I can't convert bigint to string storage, which gives me a headache. My current solution is to convert bigint to string, and then add an "n" to represent bigint

apprat commented 2 years ago

Now in version 2.2.1, bigint will be removed when stringify

jordanbtucker commented 2 years ago

Thanks for the suggestion. JSON5 already intrinsically supports arbitrary-precision integers, as there is no limitation on how large a number can be in a JSON5 document. In fact, JSON5 has no notion of different data types for numbers, apart from the special IEEE 754 values Infinity and NaN. The specification only documents the ways in which numbers can be represented, and it is up to JSON5 parser implementations to decide what data types those numbers should be stored as in memory.

There is nothing stopping you from writing a JSON5 document like this:

{
  // This number is 2^55, and it
  // is too large to be represented
  // accurately by an IEEE 754 64-bit
  // floating-point value.
  "bigint": 36028797018963968,
}

It is JSON5 parsers and generators that impose restrictions on how this large number is handled. For example, the reference JavaScript implementation parses that number in the same way a JavaScript library would—it converts it to closest value that is able to be represented by an IEEE 754 64-bit floating-point value. However, that library could be updated to recognize that the value is an integer that is too large and then convert it to a BigInt, or a string if BigInt isn't supported on the current platform.

Adding a BigInt representation for numbers in JSON5 is not only incompatible with ECMAScript 5, but it would only add the feature of indicating the intended data type of a number. Although you could make the case that a JSON5 number with a decimal point or an exponent is intrinsically a floating-point value, and that a hexadecimal number and a number without a decimal point or exponent are both intrinsically integers, there is no intrinsic way to indicate the size or signedness of those data types (e.g. 32- vs 64-bit floating-point, 8- vs 16- vs 32- vs 64-bit vs arbitrary-precision integer, and signed vs unsigned). In other words, is the JSON5 value 100 a byte, 16-bit integer, 32-bit integer, 64-bit integer, or a BigInt, and is it signed or unsigned? There isn't a way to indicate that in JSON5 because it does not impose those kinds of data type restrictions. Adding a representation for BigInt when there are no representations for other integer types would be inconsistent.

jordanbtucker commented 2 years ago

I created a replacer function and a reviver function for BigInt that both work with JavaScript implementations of JSON and JSON5. It converts BigInts to and from strings.

const value = -123n
const json5 = JSON5.stringify(value, bigIntReplacer)
// json5 == `'-123n'`
const json5 = `'-123n'`
const value = JSON5.parse(json5, bigIntReviver)
// value == -123n
apprat commented 2 years ago

I created a replacer function and a reviver function for BigInt that both work with JavaScript implementations of JSON and JSON5. It converts BigInts to and from strings.

Thanks, but converting to a string may lead to wrong judgments, I still hope to support this function, although it is indeed not compatible with ES5, but isn't the purpose of json5 to make up for the deficiencies of json?

jordanbtucker commented 2 years ago

I would not say that JSON's lack of numeric data type indicators is a deficiency. It's a feature that makes JSON platform agnostic and interoperable. As I already explained, JSON and JSON5 already support arbitrary-precision integers. If a JSON5 parser cannot handle large numbers, then it is not a deficiency of JSON5—it's a deficiency in the JSON5 parser or the platform. In other words, if a JSON5 parser encounters an integer that is too large for its platform's largest fixed-precision integer type, then it may read it as an arbitrary-precision integer (e.g. BigInt in JavaScript) instead, given the parser's platform has one.

bogdanbiv commented 2 years ago

I would not say that JSON's lack of numeric data type indicators is a deficiency.

I would say that given in ECMA-232 BigInt is standardized as 1n, having a different behavior in JSON parser/s would be a major headache. At least it should be allowed as a hint or be ignored. It's useful for humans parsing the document too.

/my $0.02