Bits on the Wire
tbray.org
tbray.org
Much like type systems in general, you always have a schema, and you always have to worry about what happens when someone adds a field. You just get to choose whether it's explicit and you have to type it alllll the way out allllll the time, or whether it's implicit, and is defined as "whatever all the usages are everywhere".
Just as gradual typing is taking over the world (TypeScript, MyPy, etc.), I predict success for something that lets you gradually add schemas to JSON.
Except when it's not you that are flexible but other parties, and they express that flexibility not only by adding but also removing or modifying fields without notice :/
Useful context for the youngsters: Tim invented XML. I mean, techically, there were a few other people who helped write the spec, but Tim was using more-or-less XML in shipped applications before they got involved.
In my book, that means his opinion about the importance of bits on the wire is pretty weighty, but you also shouldn't discount the possibility that he's in some sense constitutionally inclined toward standardized data formats.
About other data formats:
I have some experience with CBOR which I regret; it's more compact than JSON, but it's usually not significantly more compact than gzipped JSON, and it's usually slower than JSON, which is saying something, and is surprising given that no scanning for delimiters is needed. Its only real advantage is that you can safely include binary blobs. It's worth noting that originally CBOR was part of MessagePack until its author decided to fork it off and name it after himself, Carsten Bormann.
Cap'n Proto, FlatBuffers, and SBE (which I guess is too obscure for Tim to mention) get their "deserialization in negative nanoseconds" by virtue of not deserializing; instead, the respective libraries access the desired fields of the serialized data in place, which involves an extra pointer indirection or two and possibly some byte swapping, so it's a little slower than accessing fields of native structs. But it means you don't have to parse the entire data structure, just the parts you're accessing, so you can do things like memory-map a read-only data file instead of parsing it. In many cases, even if you're accessing the whole thing, saving the extra memory copy is actually worth more performance than avoiding the byte-swapping and indirections. This is not a new idea — COBOL was based on it, though without these systems' extensibility and consequently without the cost of the extra indirections — but it's an extremely effective idea in many contexts.
All of FlatBuffers, Cap'n Proto, SBE, Protobufs, Thrift, and I think Avro do have support for adding new fields, contrary to what Tim says about binary formats in his note; but they mostly do presuppose that those new fields are being defined by some central authority, because there are things like sequentially assigned field IDs, so certainly you don't have the level of safe extensibility that you have in JSON (or HTTP or RFC-822 mail or HTML forms or SNMP ASN.1 BER data or, of course, XML and HTML tags and attributes).
But, I was there, and it's an interesting story: https://www.tbray.org/ongoing/When/200x/2008/02/10/XML-Peopl...
BTW, it's mentioned in another thread above that you're not sending a Content-Type header — are you doing that on purpose? I haven't tried doing that since HTTP/0.9 days and I'm surprised it works (i.e., that modern browsers sniff the body and render it as HTML).
What I'm getting at here is, OIDs and URIs are globally namespaced. When I decide to add my own custom foo to a format, OIDs let me go get myself an arc and assign foo an OID from that arc, and URIs let me go get myself an FQDN and then assign foo a URL with that FQDN. In HTML if I just add a foo attribute that collides with everybody else's foo attribute, in RFC-822 mail my foo header can collide with anybody else's foo header. And so on.
I think this is sort of like how Wikis don't work in theory but do work in practice.
One nitpick: I don't think the extensibility of SNMP is due to ASN.1 but due to the key-value semantics of SNMP. It's true that the keys are OIDs, and the OIDs are delegated to organizations to avoid collisions (by the ITU I guess), but if you have a field in some arbitrary ASN.1 syntax that is just an OID, that doesn't give you any kind of backward-compatible extensibility. However, although I spent a couple of years struggling with SNMP on a daily basis, I'm not an expert on ASN.1 by any means, so I could be mistaken about this.
OIDs are arranged in a hierarchy, so anybody who already has an arc can just delegate you an arc from their part of the hierarchy, much the same way foo.example could delegate kragen.foo.example to you, and then you could delegate tialaramex.kragen.foo.example from that to me and so on.
The IETF hijacked the 1.3.6.1 arc, by basically arguing that if hypothetically the US Department of Defence were asked to delegate them the 1.3.6.1 arc from its 1.3.6 arc it would doubtless agree, and so no need to actually ask...
For example 1.3.6.1.5.5.7.3.1 is "serverAuth" the OID used to indicate that an X.509 certificate is intended to identify a TLS Server, that was assigned by the IETF's PKIX many years ago.
But the IETF has an arc under 1.3.6.1 for giving out OID arcs to anybody who needs one, 1.3.6.1.4.1, you can just fill out a form for IANA explaining why you need one (e.g. to make some new SNMP features work) and you'll get an arc back typically within a few days. e.g. 1.3.6.1.4.1.44947 is ISRG, the charity which provides the Let's Encrypt service.
Colliding HTML tag names has been a problem, albeit a small one, even inside "standard" HTML itself because of the conflict between WHATWG and W3C for years. The small number of web browsers with significant market share made this less serious than it might be. As to people redefining MIB OIDs, I can't help idiots, I would regard every instance of this happening as a bug in the later definition.
foo SEQUENCE { corge INTEGER, grault OBJECT IDENTIFIER }
you can't compatibly augment it with a new field quux as foo SEQUENCE { corge INTEGER, grault OBJECT IDENTIFIER, quux OBJECT IDENTIFIER }
and it doesn't help you at all that grault and quux are both OBJECT IDENTIFIERs.Which HTML tag names had collisions? I can't think of any at the moment, but admittedly I'm no HTML expert, though I've been reading HTML specs since HTML+ and before.
I'm more interested in problems not happening than on having someone to blame the problems on.
Yes, you're correct that you can't just shove arbitrary things into ASN.1 in this way and so ASN.1 itself is arguably not where the extensibility is, that's fair.
What I mean by "collision" is something like the following: one person (say, Hixie) defines <c> in their browser or stylesheet to mean "canonical name" while another person (say, the W3C) defines <c> to mean "category", resulting in problems when you try to view documents written for one browser using the other browser. I don't know of anything like this having happened in HTML, ever.
But is there a similar thing that can be done to make a PostScript XUID from a UUID? PostScript supports only 32-bit integers and not 128-bit integers, but you can use four 32-bit integers, with some prefix.
It has one advantage over YAML though, with JSON you know when you're not at the end of the file :-)
If I remove them, comments are kind of only useful for things like initial config files or what have you. Which might be fine for your use case, but JSON broadly is not about making configuration files - this is more suited for something like YAML.
If you preserve them - how is that different from a key-value just named "comment": "Here's my comment"? (And if the answer is "because it might not crash poorly coded applications," that's more of a discussion about the application than it is about comments in JSON)
The word “Notation” in JSON and the fact that JSON allows an arbitrary quantity of ignored bytes in any object (whitespace) imply that comments would have been just fine. How many JSON processors are required to preserve whitespace? (Ignorant here, I’ll take any informed answer and learn from it.)
Further, having multiple comments with the same field name is invalid JSON I believe, as keys must be unique? Though I may be wrong. (however, if keys _must_ be unique, then comment authors could encode the referent in the comment key, possibly).
True, but that's a pretty big use case to dismiss with "only". I don't think people want their json api responses to be able to include comments, but it's definitely convenient to be able to comment out parts of a config file. How/if to expose that through the deserializer is an interesting question, it would be fine with me if it dropped them.
> I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't.
* https://web.archive.org/web/20120507093915/https://plus.goog...
Basically: he didn't want people to start putting in pragmas in comments.
2012 discussion: