It must seem really strange to complain about JSON in 2026, but I never got over how fake it is.
Data in a JSON file is supposed to represent something regardless of programming language used, but does it really?
Zeroes
Let's start with this simple JSON - [0, -0, 0.0, -0.0]. What is it, and which values here are distinct, and which are the same.
In JavaScript this parses to:
- float 0.0
- float -0.0
- float 0.0
- float -0.0
In Python or Ruby this parses to:
- int 0
- int 0
- float 0.0
- float -0.0
Does JSON 0 mean the same thing as -0, or the same as 0.0? Well, nobody can agree on that, because JSON only fakes it.
Even worse, just passing this JSON through a pretty printer can change it arbitrarily.
json_pp (part of Perl, preinstalled with OSX and most other Unix systems) returns [0, 0, 0, 0]. Which matches neither JavaScript nor Ruby/Python.
json_xs (also part of the exact same Perl, preinstalled with OSX and most other Unix systems) returns [0, 0, 0, -0] instead. This isn't even idempotent, passing it through json_xs twice gets us to [0, 0, 0, 0]!
jq preserves all numbers at least. This online pretty printer turns it to [0, 0, 0, 0]. This one goes with [0, 0, 0.0, -0.0].
Pretty printers are quite trivial, but data sent from one program to another can easily go through some database or proxy or something else that would mangle it.
And how other languages do it? Most follow Ruby/Python, but some go for JavaScript, and good luck guessing which way it goes.
Big integers
OK, so you don't care for zeroes. Let's look at something that matters a lot more - big integers.
3**39 = 4052555153018976267 is not even anything special, just a 64-bit integer. Can JSON represent it? Well, it depends.
Ruby, Python, json_pp, and json_xs all let it pass through correctly.
Some random pretty printers? This one mangles it. As does this one. As does JavaScript, despite big integers existing in JavaScript.
But what if we try 3**80 = 147808829414345923316083210206383297601 which is a 128-bit integer? The two online ones above mangle it to a double again, but interestingly json_pp and json_xs turn it into a string now! It's "147808829414345923316083210206383297601", not even a number, but at least it's not rounded.
Big decimals
Up to this point things sort of work if we avoid JavaScript, Go, and other broken languages. But now it gets worse for all languages.
In principle big decimals are 100% representable in JSON. Does any language even try?
Ruby will represent them as strings, weirdly "0.33333333333333333333333333333333e0". Python will just refuse with Object of type Decimal is not JSON serializable.
If you actually pass 0.33333333333333333333333333333333 through any pretty printer other than jq, it will round it to double precision, or something close to it.
Every language has its own JSON flavor
And so, JSON is a lie. JavaScript JSON and Python JSON are not the same at all! Ruby actually seems to match Python perfectly, in a rare interop success story.
Other languages might match one of these two, but usually they do something slightly different, like some do int32+float64, some do int64+float64, Rust somehow does "I'm not even going to try, here's a bunch of accessors, figure it out by yourself" (but even that up to 128-bit only, no bigints).
And what's worse - your data might go through proxies, databases, and other steps that can mangle it.
This isn't anything exotic - integers bigger than 32 bits are a very common data type.
Is it just numbers?
Numbers are the biggest area of disagreement, but there's another with objects.
Depending on implementation, order of fields might or might not be preserved. It's not so much an interoperability problem as it is a headache as serializing an identical object might result in multiple different JSON representations.
Surprisingly, the standard doesn't actually ban duplicate keys with the same name! It only says that "The names within an object SHOULD be unique", and advises against using duplicate names. It's been a very long time since I've last seen duplicate keys in the wild.
And technically there's one more area where the standard admits implementation differences with handling Unicode, but I haven't seen that in the wild either.
The Mystery
Here's a mystery I could never quite figure out. If JSON is really programming language specific anyway, why doesn't each programming language define their own JSON-like format, to express what it can represent? Beyond solving numbers, it would at least have date and time objects, in JSON typically escaped as strings. It could have proper big decimals, tuple/array indexed objects, and whatever extra stuff like symbols a given language uses.
And since we're at it, they could also add comments to the format.
As far as I can tell, no language ever seriously tried to do this, they all just use their own flavor of JSON and pretend like it's standard.



No comments:
Post a Comment