JSON, JavaScript, and numeric types

One gap in the JSON spec is its coverage of numeric types. Aside from forbidding NaN and infinity, the RFC doesn't limits the range or precision of numeric values:
The representation of numbers is similar to that used in most programming languages. A number contains an integer component that may be prefixed with an optional minus sign, which may be followed by a fraction part and/or an exponent part.

Octal and hex forms are not allowed. Leading zeros are not allowed.

A fraction part is a decimal point followed by one or more digits.

An exponent part begins with the letter E in upper or lowercase, which may be followed by a plus or minus sign. The E and optional sign are followed by one or more digits.

Numeric values that cannot be represented as sequences of digits (such as Infinity and NaN) are not permitted.

Despite the spec claiming the opposite, this is unlike most programming languages. Formal languages specify ranges for values or defer to standards like IEEE 754.

One workaround is to assume JavaScript semantics: every number is a double. With these semantics, round-tripping a JSON document through JavaScript is lossless.

The alternative, as implemented by Java JSON libraries like Crockford's, Jackson and JSON.simple is to support several numeric types: integer, floating point, and arbitrary precision. In general, documents created with these libraries cannot be roundtripped through JavaScript. Large values like 9007199254740993 need to rounded to a nearby double.

Paste that value into this JavaScript interpreter for an example. (Won't work in feed readers!)



For measurements and counts, the numbers have to be extremely big for rounding to occur. It won't impact epoch dates in the next 285,000 years.

If you're using numbers for identifiers, you have 15 safe digits to work with. Current Twitter tweet IDs are only 11 digits. But if you encode a Java UUID to JSON as two longs, browser roundtrips will corrupt data.

Like every data interchange format, JSON has its gaps and it helps to be mindful of them when mapping between systems.

No comments: