JSON support for BigInt in Chrome/V8

# Anders Rundgren (6 years ago)

var small = BigInt("5"); var big = BigInt("5555555555555555555555555500003"); JSON.stringify([big,small]); VM330:1 Uncaught TypeError: Do not know how to serialize a BigInt     at JSON.stringify (<anonymous>)     at <anonymous>:1:6

JSON Number serialization has apparently reached a new level (of confusion).

Personally I don't see the problem.  XML did just fine without hard-coded data types.

The JSON type system is basically a relic from JavaScript.  As such it has proved to be quite useful. However, when you are outside of that scope, the point with the JSON type system gets pretty much zero since you anyway need to map extended types.

Oracle's JSON-B solution which serializes small values as Number and large values as String rather than having a unified serialization based on the underlying data type seems like a pretty broken concept although indeed fully conforming to the JSON specification. "Like the Devil reads the Bible" as we say in Scandinavia :-)

Adding a couple of double quotes is a major problem?  If so, it seems like a way more useful project making quotes optional for keys (named in a specific way), like they already are in JavaScript.

Yeah, and of course adding support for comments.

Anders

# J Decker (6 years ago)

On Sat, Jul 14, 2018 at 1:36 AM Anders Rundgren < anders.rundgren.net at gmail.com> wrote:

var small = BigInt("5"); var big = BigInt("5555555555555555555555555500003"); JSON.stringify([big,small]); VM330:1 Uncaught TypeError: Do not know how to serialize a BigInt at JSON.stringify (<anonymous>) at <anonymous>:1:6

is BigInt the only way to create a BigInt ? Or did they also implement the 'n' suffix, which I noted here tc39/proposal-bigint#24 would easily distinguish bigint from other numbers; and be easy to add on the parsing side; and call BigInt(xxx) instead of Number(xxx).

var small = 5n; var big = 5555555555555555555555555500003n;

n suffix as from tc39/proposal-bigint

JSON Number serialization has apparently reached a new level (of confusion).

Personally I don't see the problem. XML did just fine without hard-coded data types.

The JSON type system is basically a relic from JavaScript. As such it has proved to be quite useful. However, when you are outside of that scope, the point with the JSON type system gets pretty much zero since you anyway need to map extended types.

Oracle's JSON-B solution which serializes small values as Number and large values as String rather than having a unified serialization based on the underlying data type seems like a pretty broken concept although indeed fully conforming to the JSON specification. "Like the Devil reads the Bible" as we say in Scandinavia :-)

Adding a couple of double quotes is a major problem? If so, it seems like a way more useful project making quotes optional for keys (named in a specific way), like they already are in JavaScript.

Yeah, and of course adding support for comments.

I'd rather not see numbers converted to strings; that would be required to allow application handling of values; at a layer higher than JSON core itself. It is nice that JSON keeps numbers as numbers and strings as strings without needing intimite knowledge about the actual 'types' they end up in.

Comparing numeric length would be a half/useless solution since bigints are required to interop with other bigints only; so small numbers couldn't be 'guessed' and the application would have to provide a reviver.

# Anders Rundgren (6 years ago)

On 2018-07-15 04:27, J Decker wrote:

On Sat, Jul 14, 2018 at 1:36 AM Anders Rundgren <anders.rundgren.net at gmail.com <mailto:anders.rundgren.net at gmail.com>> wrote:

var small = BigInt("5");
var big = BigInt("5555555555555555555555555500003");
JSON.stringify([big,small]);
VM330:1 Uncaught TypeError: Do not know how to serialize a BigInt
      at JSON.stringify (<anonymous>)
      at <anonymous>:1:6

is BigInt the only way to create a BigInt ?  Or did they also implement the 'n' suffix, which I noted  here tc39/proposal-bigint#24 would easily distinguish bigint from other numbers; and be easy to add on the parsing side; and call BigInt(xxx) instead of Number(xxx).

This problem is related to the BigInt object itself. If you create such using the 'n' notation you get the same result.

If you want to use BigInt with JSON you have to serialize it yourself:

var small = BigInt(5n); var big = BigInt(5555555555555555555555555500003n); JSON.stringify([big.toString(),small.toString()]);

which generates ["5555555555555555555555555500003","5"]

Anders

# J Decker (6 years ago)

On Sat, Jul 14, 2018 at 9:23 PM Anders Rundgren < anders.rundgren.net at gmail.com> wrote:

On 2018-07-15 04:27, J Decker wrote:

On Sat, Jul 14, 2018 at 1:36 AM Anders Rundgren < anders.rundgren.net at gmail.com <mailto:anders.rundgren.net at gmail.com>> wrote:

var small = BigInt("5");
var big = BigInt("5555555555555555555555555500003");
JSON.stringify([big,small]);
VM330:1 Uncaught TypeError: Do not know how to serialize a BigInt
      at JSON.stringify (<anonymous>)
      at <anonymous>:1:6

is BigInt the only way to create a BigInt ? Or did they also implement the 'n' suffix, which I noted here tc39/proposal-bigint#24 would easily distinguish bigint from other numbers; and be easy to add on the parsing side; and call BigInt(xxx) instead of Number(xxx).

This problem is related to the BigInt object itself. If you create such using the 'n' notation you get the same result.

If you want to use BigInt with JSON you have to serialize it yourself:

Yes; and I did forget to mentions erilaization side but the serlizer could do an additional type check and emit and appropriate thing. I thought the replacer could be used- but the output of replacer would have to type check to see if it's a bigint too.... v8/v8/blob/master/src/json-stringifier.cc#L305 case BIGINT_TYPE: hmm and digging some more there's lots of eexcpetions thrown...

does Number( "5n" ) ? result in a bigint? No....

Number( "5n" )
NaN
var a = 5n
a
5n

var small = BigInt(5n); var big = BigInt(5555555555555555555555555500003n); JSON.stringify([big.toString(),small.toString()]);

which generates ["5555555555555555555555555500003","5"]

Anders

# Anders Rundgren (6 years ago)

On 2018-07-15 08:17, J Decker wrote: <snip>

If you want to use BigInt with JSON you have to serialize it yourself:

Yes; and I did forget to mentions erilaization side but the serlizer could do an additional type  check and emit and appropriate thing.

It is the "appropriate thing" that is problem; the rest is trivial.

Anders

# Andrea Giammarchi (6 years ago)

We miss a fundamental feature in JS, the ability to understand if a native constructor can be used with new or not.

BigInt("5555555555555555555555555500003"); 5555555555555555555555555500003n

new BigInt("5555555555555555555555555500003"); VM51:1 Uncaught TypeError: BigInt is not a constructor

Uint8Array([]) VM54:1 Uncaught TypeError: Constructor Uint8Array requires 'new'

new Uint8Array([]) Uint8Array []

Without that knowledge, any attempt to even think about a solution that would scale not only with BigInt but with everything else, is kinda futile.

Best .

# J Decker (6 years ago)

On Tue, Jul 17, 2018 at 1:48 AM Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

We miss a fundamental feature in JS, the ability to understand if a native constructor can be used with new or not.

BigInt("5555555555555555555555555500003"); 5555555555555555555555555500003n

new BigInt("5555555555555555555555555500003"); VM51:1 Uncaught TypeError: BigInt is not a constructor

typeof(5n)
"bigint"

Uint8Array([])

# Andrea Giammarchi (6 years ago)

fair enough, so everything that is not object or null should never use new. Is this somehow an indirect rule based on current specs or actually part of the specification?

# Andrea Giammarchi (6 years ago)

also, how would you "cast" a BigInt from string to BigInt ?

# Andrea Giammarchi (6 years ago)

P.S. eval / Function is obviously not an answer

# Andrea Giammarchi (6 years ago)

actually, never mind ... but I find it hilarious that BigInt('55555555555555555550000000000000000000001') works but BigInt('55555555555555555550000000000000000000001n') doesn't ^_^;;

Anyway, there is an easy pattern to go around this issue (and all others), will come back on this.

Best

# Anders Rundgren (6 years ago)

On 2018-07-17 13:27, Andrea Giammarchi wrote:

actually, never mind ... but I find it hilarious that BigInt('55555555555555555550000000000000000000001') works but BigInt('55555555555555555550000000000000000000001n') doesn't ^_^;

This is how it works in Java as well. 55555555555555555550000000000000000000001n is a numeric literal.

Other issues like "new" are more difficult to understand the rationale behind.

# Cyril Auburtin (6 years ago)

It would be great to have

JSON.stringify({x: 5n, y: BigInt('6')}) === '{"x":5n,"y":6n}'
JSON.parse('{"x": 3n}') // {x: 3n}

I don't know how feasible it would be, maybe have a new JSON5 object if JSON can't be changed for some reasons

# Andrea Giammarchi (6 years ago)

My idea is that JSON.stringify(new Uint8Array([1, 2, 3])); is also an issue, not only BigInt.

if every value could be represented as {{type: 'BigInt', value: '55555555'}, {new: 'Uint8Array', value: [1, 2, 3]}, {type: 'string', value: 'dastring'}, {type: 'number', value: 123}, {new: 'String', value: 'as wrap'}} and resurrected later on it's basically problem solved except for Weak* and Symbol, unless it's a global one, and it'd be OK.

That transformation would be compatible also with all circular-json like libraries I know (or I've written).

# Andrea Giammarchi (6 years ago)

actually, {type: 'String', value: ''} ... so the rule is: usable as class ? {new: 'ClassName', value: 'how to construct it'} : {type: 'Primitive', value: 'how to create it'} and the unserialized value uses new global[obj.new](obj.value) or global[obj.type](obj.value) to recreate the value.

# Anders Rundgren (6 years ago)

On 2018-07-17 17:44, Cyril Auburtin wrote:

It would be great to have

JSON.stringify({x: 5n, y: BigInt('6')}) === '{"x":5n,"y":6n}'
JSON.parse('{"x": 3n}') // {x: 3n}

I don't know how feasable it would be, maybe have a new JSON5 object if JSON can't be changed for some reasons

If compatibility with other platforms which already have addressed this issue is an objective, there are essentially only three workable schemes:

  • Use JSON exactly as specified [*]; without restrictions on numbers. Example: Microsoft's Json.NET.

  • Use an adaptive I-JSON scheme. Example: Oracle's JSON-B.

  • Use use a normalized I-JSON scheme. Example: Close to a de-facto standard for systems targeting multiple platforms as well as for [probably all] IETF standards defining JSON structures.

Anders

*] Ignoring footnote-like interoperability considerations for JSON numbers.

# Jordan Harband (6 years ago)

You already can't use new with Symbol, and you don't ever want to use new with a primitive's constructor anyways.

# Waldemar Horwat (6 years ago)

On 07/17/2018 04:27 AM, Andrea Giammarchi wrote:

actually, never mind ... but I find it hilarious that BigInt('55555555555555555550000000000000000000001') works but BigInt('55555555555555555550000000000000000000001n') doesn't ^_^;;

That's no different from how other built-in types work. String('"foo"') doesn't give you the same string as the string literal "foo".

 Waldemar
# Rob Ede (6 years ago)

The way I see it is that JSON is kind of a thing by itself even without JavaScript and we shouldn’t be beholden to the JS syntax of representing Bigints (123n vs 123) in JSON.

I think changing the behaviour of JSON.parse and introducing JSON5 namespace (or whatever) are both on the right track but meeting in the middle and extending the syntax of the existing JSON.parse/stringify with an options object that specified how to decode/encode bigints (string/number) would be the best approach.

For example, the Twitter API returns tweet ids as 64-bit ints. Granted they also return the is as a string for just this reason. But I don’t expect them to start including a third is field just to add an “n” onto it.

# Andrea Giammarchi (6 years ago)

I guess a better example would've been Boolean('false') returns true, but yeah, I've moved slightly forward already with everything, if you read other messages.

.

# Michael J. Ryan (6 years ago)

Out of bounds as you'd still have to parse it, but for encoding, could add BigInt.prototype.toJSON ...

# Jordan Harband (6 years ago)

You can permanently fix any such type-checks by function isObject(x) { return x && (typeof x === 'object' || typeof x === 'function'); }, or function isObject(x) { return x && Object(x) === x; }, etc.

# Isiah Meadows (6 years ago)

The way this conversation is going, we might as well just create a schema-based JSON serialization DSL for both parsing and stringifying. But I don't really see that as helpful in the language itself at least as a mandatory part of the spec (maybe an optional built-in module).

I've in the past few months seen similar things come up a few times already. I like the idea of a built-in schema-based JSON validator + parser (it'd be faster than what we currently have), but most things out there suck in some way, mostly just being boilerplatey, and there's a lot of design work to get out of the way first before you can come up with something that doesn't.

But as it stands, the only things I'd support for the JSON global itself are:

  1. Adding separate prototypes for JSON.stringify(source, options) and JSON.parse(source, options), so it's easier to extend and comprehend the arguments.
  2. Adding an option to parse anything consisting of purely digits (no exponent or decimal) as a BigInt, regardless of size.
  3. Adding an option to stringify BigInts into integer-only numbers and normal numbers into unconditional floats.

These could be either separate methods or part of a 4th options argument.


Isiah Meadows me at isiahmeadows.com, www.isiahmeadows.com

# Anders Rundgren (6 years ago)

Serializing BigInts as quoted strings is compatible with Java JSON-B, Json.NET and can be poly-filled for older JS implementations.

In addition, this is also compatible with non-schema based parsing.

AFAIK, no IETF standard to date which depends on extended numbers (like JOSE) break the I-JSON recommendations.

Anders

# J Decker (6 years ago)

On Tue, Jul 17, 2018 at 9:16 PM Isiah Meadows <isiahmeadows at gmail.com>

wrote:

The way this conversation is going, we might as well just create a schema-based JSON serialization DSL for both parsing and stringifying. But I don't really see that as helpful in the language itself at least as a mandatory part of the spec (maybe an optional built-in module).

I've in the past few months seen similar things come up a few times already. I like the idea of a built-in schema-based JSON validator + parser (it'd be faster than what we currently have), but most things out there suck in some way, mostly just being boilerplatey, and there's a lot of design work to get out of the way first before you can come up with something that doesn't.

But as it stands, the only things I'd support for the JSON global itself are:

  1. Adding separate prototypes for JSON.stringify(source, options) and JSON.parse(source, options), so it's easier to extend and comprehend the arguments.
  2. Adding an option to parse anything consisting of purely digits (no exponent or decimal) as a BigInt, regardless of size.

This won't work....

{ a : 123, b : 123n }
{ "a":123 ,
  "b":123 }

function test( json ) { var c = json.a * 5; var BIc = json.b * 5n; }

if long numbers only translate to bigint (and small as Number); the calc for 'BIc' fails. if everything is translated to bigint the calc for 'c' fails.

  1. Adding an option to stringify BigInts into integer-only numbers and

normal numbers into unconditional floats.

These could be either separate methods or part of a 4th options argument.

Well; Since JSON (JavaScript Object Notation) there's now available to JS a feature that an 'n' suffix can be applied to a number. Seems JSON should just inherit that.

Although I would like to see a better method than eval() to translate the input string from JSON for say { d : 123n }; right now within JS I'd have to use EVAL; in V8 I could just create a BigInt::new()....

(and RE: eval, not saying it's a GOOD solution; it's just apparently the only solution ATM; other than splicing the string.)

# Andrew Paprocki (6 years ago)

On Wed, Jul 18, 2018 at 5:03 AM, J Decker <d3ck0r at gmail.com> wrote:

Well; Since JSON (JavaScript Object Notation) there's now available to JS a feature that an 'n' suffix can be applied to a number. Seems JSON should just inherit that.

json.org states:

"It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999."

ECMA-404 states:

"JSON stands for JavaScript Object Notation and was inspired by the object literals of JavaScript aka ECMAScript as defined in the ECMAScript Language Specification, Third Edition [1]. However, it does not attempt to impose ECMAScript’s internal data representations on other programming languages. Instead, it shares a small subset of ECMAScript’s syntax with all other programming languages."

The 3rd edition did not contain the 'n' suffix, and neither indicate that new ES features should be added to JSON.

# Isiah Meadows (6 years ago)

This won't work....

{ a : 123, b : 123n }
{ "a":123 ,
  "b":123 }

function test( json ) { var c = json.a * 5; var BIc = json.b * 5n; }

if long numbers only translate to bigint (and small as Number); the calc for 'BIc' fails. if everything is translated to bigint the calc for 'c' fails.

I think you missed my point: I'm suggesting an extra option to where floats are parsed differently from integers.

// JSON
{"a": 123.0, "b": 123}

// Parsed normally
{a: 123, b: 123}

// Parsed with option
{a: 123, b: 123n}

So given this, the test would be exactly what's expected with the option.


Isiah Meadows me at isiahmeadows.com, www.isiahmeadows.com

# kai zhu (6 years ago)

reposting due to previous mail-rejection (vpn issue with gmail in china)

You already can't use new with Symbol, and you don't ever want to use new with a primitive's constructor anyways.

this rule would be okay if we limit the number of primitive-types in the language to a small-number (maybe add BigDecimal, but that's it), so its easy to remember. i'm already concerned that we have one too many needless primitives (Symbol should've been an object similar to Promise, and even more so since its use-case is marginal).

adding more primitives at this point, will only make this pedantic-rule look more like a wart, and trip-up beginners (and their prejudice on the language's inconsistencies). it also complicates integration-work on web-projects, due to difficulty baton-passing new primitives around via JSON, and having to continually refactor type-checks that rely on typeof.

# Jordan Harband (6 years ago)

I'm not sure why anything needs remembering - with no other knowledge except "how the thing you're trying to create is used", I'd hope that it's apparent whether it's an object or a primitive.

# T.J. Crowder (6 years ago)

Not having JSON support for BigInt is a big problem. But the fact exists that JSON does not cover everything. It doesn't cover Dates, Maps, Sets, Symbols...

Until/unless the successor to JSON (whatever it may be) is created and adopted, a process that will take years, let's take a pragmatic approach similar to the pragmatic approach taken in relation to Dates: Abuse a string.

BigInt.prototype.toJSON = function() {
    return `/BigInt(${this.toString()})/`;
};

Then this:

console.log(JSON.stringify({n:10n}));

outputs

{"n":"/BigInt(10)/"}

Do I like it? Not even a little bit. But as a pragmatic way forward, providing toJSON on BigInt's prototype and having it produce something along these lines seems like Better Than Nothing™. Date's toJSON produces a string in a readily-recognized format, after all. I'd also suggest BigInt.fromJSON which validated and parsed the string in that format.

This would put us where Dates are now, but without competing standards for them (ISO string vs./Date(epochval)/).

-- T.J. Crowder

# Anders Rundgren (6 years ago)

Thanx T.J.

With your suggestion there are now not less than FIVE proposals on the table for dealing with BigInt JSON serialization:

  • * RFC8259: 123456789123456789123456789
  • ES6 enhanced: 123456789123456789123456789n
  • Typed: "/BigInt(123456789123456789123456789)/"
  • * Adaptive: "123456789123456789123456789" respectively 123456789
  • * Conservative: "123456789123456789123456789"

Maybe Carsten Bormann after all is right, it is time to jump the JSON ship!

Before the industry takes the leap to CBOR, I personally stick to the conservative path because it appears to be compatible ("usable" is maybe a better word) with just about everything out there.

I wouldn't completely ignore the fact that XML did just fine without any explicit type information at all. OpenAPI addresses this for Date to take an example. They are though still grappling with BigInt :-)

Cheers, Anders

* Denotes implemented/in use

# Michael Theriot (6 years ago)

In a language with arbitrary integer precision, Python 3 for example, the way to parse a "BigInt" would just be a plain, human readable number without quotes. The way to serialize it is the same. Any other kind of representation is out of spec, a workaround, and belongs in userland.

I think BigInt should serialize the same, not as strings or anything that is not a number. JSON.parse being unable to parse back into BigInt is a separate issue. It is solvable by using better parsing methods, not the convenient built-in one which has other issues. E.g. a streaming JSON parser that lets you inspect the key name and string being parsed can handle this. Case solved and you can also redesign your code so you are not creating a temporary object every single parse that you most likely copy into actual objects later.

Not serializing BigInt is questionable to me but even that can be solved in userland.

# Isiah Meadows (6 years ago)

Not serializing BigInt is questionable to me but even that can be solved in userland.

This is pretty easy for JSON.stringify, at least: you specify a reviver that coerces them to numbers:

JSON.stringify(object, null, (k, v) => typeof v === "bigint" ? Number(v) : v)

The deserialization of that is trickier, but it's easy worked around.


Isiah Meadows me at isiahmeadows.com, www.isiahmeadows.com

# Anders Rundgren (6 years ago)

On 2018-07-28 16:10, Isiah Meadows wrote:

Not serializing BigInt is questionable to me but even that can be solved in userland.

This is pretty easy for JSON.stringify, at least: you specify a reviver that coerces them to numbers:

JSON.stringify(object, null, (k, v) => typeof v === "bigint" ? Number(v) : v)

This code did not run in Chrome 67 and if it had, it would have truncated values which is probably not what you want.

Although not super elegant, the following code works and would presumably also work with predecessors using emulated BigInts:

var object = { big: BigInt(555555555555555555555555555n).toString(),
                small: 55};
JSON.stringify(object);

The deserialization of that is trickier, but it's easy worked around.

By sticking to the conservative/boring approach you can use it today:

var input = JSON.parse('{"big":"555555555555555555555555555","small":55}', (key, value) =>
   key == 'big'
     ? BigInt(value) // return true BigInt
     : value     // return everything else unchanged
);
console.log(input);

Anders

# Ranando King (6 years ago)

Why not just use DataURL syntax, something like this:

{
  "field1":
"data:json/bigint,12345678901234567890123456789012345678901234567890123456789012345678901234567890",
  ...
}

This way, even as other objects pop up to be serialized, all that would be needed is another mime type in the format "json/<typename>". I could even

see letting the "<typename>" portion hold the non-lowercased, original

class name to make it even faster to deserialize such fields without knowing all possible mime types in advance. Still 100% compatible with existing JSON. Still 100% human readable/writable. Very easy to implement, and self consistent.

# Anders Rundgren (6 years ago)

On 2018-07-28 16:52, Ranando King wrote:

Why not just use DataURL syntax, something like this:

{
   "field1": "data:json/bigint,12345678901234567890123456789012345678901234567890123456789012345678901234567890",
   ...
}

This way, even as other objects pop up to be serialized, all that would be needed is another mime type in the format "json/<typename>". I could even see letting the "<typename>" portion hold the non-lowercased, original class name to make it even faster to deserialize such fields without knowing all possible mime types in advance. Still 100% compatible with existing JSON. Still 100% human readable/writable. Very easy to implement, and self consistent.

I think the issue is rather: What problem do we want to solve?

It is pretty obvious that there is no "perfect" solution.

XML proves that there is no need for explicit type information in an information exchange format. Most sophisticated systems map keys in some way making explicit type information redundant. That JSON do have a set of distinct data types is great, but extending that type scheme outside of the original JavaScript core, IMO only creates problems. Nobody (in their right mind) would even think of designing a typed format where everything from a byte to BigDecimal would be represented as a single type.

Anders

# Ranando King (6 years ago)

Don't get me wrong. I didn't suggest a means of extending JSON. I suggested a means of consistently and easily reversibly serializing anything that is not natively handled by JSON already. I think JSON is a fairly complete syntax for most purposes. I wish it had a reference type so that recursive structures could be encoded as well, but the suggestion I've just made can even be used to encode that.

# J Decker (6 years ago)

On Sat, Jul 28, 2018 at 6:57 AM Michael Theriot < michael.lee.theriot at gmail.com> wrote:

In a language with arbitrary integer precision, Python 3 for example, the way to parse a "BigInt" would just be a plain, human readable number without quotes. The way to serialize it is the same. Any other kind of representation is out of spec, a workaround, and belongs in userland.

The problem with this, 'guessing' whether is't a Number() or a BigInt() is that numbers and bigint's don't interop.

{a:123, b:123n} " { "a":123, "b":123 }" any expressions that expect B to be a BigInt() will fail, becasue it will be in an expression of other bigints.

bigInts aren't just a better Number type, but, rather require other bigints for their expressions.

# Anders Rundgren (6 years ago)

On 2018-07-28 18:07, Ranando King wrote:

Don't get me wrong. I didn't suggest a means of extending JSON. I suggested a means of consistently and easily reversibly serializing anything that is not natively handled by JSON already.

Sure, I got that. It would obviously work as well. The problem is that JavaScript's BigInt is rather late in the game. The non-JavaScript platforms already have defined BigInt support, but in an inconsistent way.

I think JSON is a fairly complete syntax for most purposes.

Yes, if you stick to the JavaScript core types defined some 15-20 years back. Outside of that things are slightly less complete, at least if you include implementations as well.

I wish it had a reference type so that recursive structures could be encoded as well, but the suggestion I've just made can even be used to encode that.

Doesn't JSON schema (disclaimer: I'm not a user), provide such things?

Anders

# Michael Theriot (6 years ago)

I think we should move away from guessing and automagically parsing our JSON. The fact is a JSON number != JS number. Perhaps in userland (or a proposal...) JSON.parse could return with a JSONNumber object which the developer decides to convert to BigInt or Number.

# Ranando King (6 years ago)

What I meant by complete is that if the value isn't an ES Number, isn't a boolean, and isn't null, it will have a string representation, or a binary representation that can be encoded as a string using base64. By using a dataUri for those cases, we can create a consistent library to handle those issues automatically, and without guesswork (no magic). If such a utility API became a standard in ES, other languages would be far more likely to adopt the standardized notation that would be provided.

# Anders Rundgren (6 years ago)

On 2018-07-28 21:21, Ranando King wrote:

What I meant by complete is that if the value isn't an ES Number, isn't a boolean, and isn't null, it will have a string representation, or a binary representation that can be encoded as a string using base64. By using a dataUri for those cases, we can create a consistent library to handle those issues automatically, and without guesswork (no magic). If such a utility API became a standard in ES, other languages would be far more likely to adopt the standardized notation that would be provided.

As I have tried (apparently in vain) to describe, the other languages already have solutions for BigInt (and much more), which the respectively authors consider both sufficient and good.

ES6 is pretty late in the game and therefore rather have to adapt itself to the other players.

These are the options: esdiscuss.org/topic/json-support-for-bigint-in-chrome-v8#content-30

  • "Conservative" works right out of the box (although in a somewhat inelegant way). It is backward compatible with many existing ES and non-ES JSON based applications.

  • "RFC8259" support would require changes to the ES6 JSON object. For parsing (JSON.parse2()), a JSONNumber object as proposed by Michael Theriot seems like a candidate.

I have limited faith in extending the (for general purpose information interchange) already pretty deficient JSON type scheme; state-of-the-art applications check indata anyway making explicit type information redundant.

Anders

# kai zhu (6 years ago)

i support @anders’ conservative scheme and opened up a github-issue to try and get it included before stage-4 [1]. this might be one of the last-opportunities to change the behavior before its set-in-stone.

there was a previous github-issue on bigint JSON-support [2] (that led to the current behavior no one is happy about), but it never discussed the conservative scheme, hence the revisit.

to summarize, the conservative scheme basically copies the same JSON-behavior as Date. users are already familiar with serializing Date, so there shouldn’t be any surprises (or at least less-surprises than throwing an error). this is the simplest, actionable, and least-offensive-to-all-parties solution i can think of (unless someone has a less-offensive-to-all idea). its also applicable in solving the same-issue for future primitives like BigDecimal.

var aa;

// we copy JSON-behavior of Date
aa = 12345678901234567890n // <bigint primitive>

aa = JSON.stringify(aa) // '"12345678901234567890"' (escaped string)
aa = JSON.parse(aa) // '12345678901234567890' (un-escaped string)
aa = BigInt(aa) // <bigint primitive> (no precision-loss)

aa = new Date() // <Date object>

aa = JSON.stringify(aa) // '"2018-07-28T09:41:47.519Z"'' (escaped string)
aa = JSON.parse(aa) // '2018-07-28T09:41:47.519Z' (un-escaped string)
aa = new Date(aa) // <Date object>

[1] github-issue - revisit: Support JSON serialisation of BigInt values tc39/proposal-bigint#162, tc39/proposal-bigint#162

[2] github-issue - [closed] Support JSON serialisation of BigInt values tc39/proposal-bigint#24, tc39/proposal-bigint#24

kai zhu kaizhu256 at gmail.com

# T.J. Crowder (6 years ago)

On Sun, Jul 29, 2018 at 9:01 AM, kai zhu <kaizhu256 at gmail.com> wrote:

i support @anders’ conservative scheme and opened up a github-issue to

try

and get it included before stage-4 [1].

I agree with you and Anders that this should be sorted out now, not as a follow-on proposal. If it's left to later, people will supply their own BigInt.prototype.toJSON and cause themselves compatibility problems down-the-line.

Don't like the raw number in quotes ("conservative" option) at all. There should be some indication that this is a bigint, just as pattern matching tells us the default Date serialization is a date. This could be achieved with just the lower-case n at the end, as in some early examples in the github issue. And to support easy two-way, BigInt(string) should support the lower-case n at the end.

aa = 12345678901234567890n; // BigInt primitive
aa = JSON.stringify(aa);    // '"12345678901234567890n"'
aa = JSON.parse(aa);        // '12345678901234567890n'
aa = BigInt(aa);            // BigInt primitive

^\d+n$ isn't much of a pattern, but it's a pattern. (Earlier in this thread I suggested /BitInt(123)/ to match Microsoft's /Date(123)/ which is unambiguous and offers a path to extendibility, but Date already goes a different way...)

This parallels Date handling and seems a reasonable stop-gap until the next thing after JSON.

-- T.J. Crowder

# Rob Ede (6 years ago)

+1 on getting this sorted before stage 4

As people have said before, JSON already supports BigInts. We of course need to preserve backwards compatibility with JS and try not to break how other languages use JSON.

I think the best way to satisfy everyone is to give ourselves some flexibility going forwards and JSONifying BigInts as strings doesn’t allow JSON to do what it can do. That and it breaks the idea that JSON.parse(JSON.stringify(x)) is a deep clone.

So, flexibility: there are two options in my head for this.

  1. An object passed to JSON.parse with options for how to deal with integers larger than Number can support. The current behaviour of misrepresenting them is the default. But other options could include converting to BigInts (or strings) if needed and always converting to BigInts (since they are non-interoperable currently). This approach allows the programmer to decide the behavior and plan for it in their code.

  2. It seems like the already suggested JSONNumber object could offer the same flexibility and guarantees though. A valueOf that returns the misrepresented Number for interop with existing numbers. A toString that gives a well represented string conversion. (Im not 100% certain of the order these two functions are used in auto-casting. On mobile or else would check spec.) A toBigInt / unwrap (monad-ish terminology) to get the true value as and when the programmer wants.

Hope these ideas seem reasonable. Scrutiny welcome.

Rob J T Ede