JSON5 – JSON for Humans
json5.org
json5.org
The only thing that JSON is really missing are comments and trailing commas. I use JSONC for that. It's what VSC uses for the config format and it works.
The reason JSON doesn't have comments [1]:
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.
Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser.
[1] http://archive.today/8FWsAI don't think your take makes sense. Comments were purposely left out of JSON to mitigate the problem described by Hyrum's law.
Smaller interface means a smaller surface to allow abuse. You're just arguing to facilitate abuse because you feel the abuse that was indeed avoided by leaving comments out is unavoidable, which is a self-contradiction.
On top of that,think about the problem for a second. Why do you feel it's reasonable to support comments in data interchange formats? This use case literally means wasting bandwidth with data that clients should ignore. The only scenario where clients are not ignoring comments if exactly the scenario that it's being avoided: abusing it for control purposes.
If you want a data interchange format to support that, you should really adopt something that is better suited for your whole use case.
> and your suggestion doesn't help with eg syntax highlighting tools for your config that will treat comments as syntax errors (...)
That's the whole point. This is by design, not a fault. Why are you pretending a language supports a feature it never supported and explicitly was designed to not support?
If you take your law seriously, this is irrelevant because the surface of abuse is on the same scale of practical infinity, so it doesn't matter that one infinity is technically smaller.
For example, based of the example in the quote: you could stick those directives from comments info #hashtags in stringy values, with the same effect that there is no interoperable way to parse values (or if you add "_key_comment" - there is no interoperable way to even parse keys as some of them need to be ignored)
So the designer has achieved no benefit by removing a valuable feature
> abuse that was indeed avoided
Nothing was avoided, you can have the exact same abuse tucked into other elements
> Why do you feel it's reasonable to support comments in data interchange formats?
Why does the author of the quote sees the obvious which you don't see even after reading the quote? Go convince him his comment makes no sense because of "data interchange"
Obviously it's not only used for data interchange in cases where every byte matters (reminder: this is a TEXT-based format) and also comments matter to humans working with this data
> adopt something that is better suited for your whole use case.
And this discussion is literally about a format supports that? But also, how does this in any way mitigate the flaws in the designer's arguments?
> Why are you pretending a language supports a feature it never supported and explicitly was designed to not support?
Same thing, why is the author of the quote makes this senseless suggestions then? Go convince him first
I don’t have anything against XML by the way, it was purely horrible to work with because people were using it in so many weird ways. Personally I prefer toml, but I guess we all have our preferences.
This actually would put JSON in a worse place than XML - while XML has an overly complex infoset, that infoset is actually defined and standardized. Representing "a property with a comment on the property name and one before and after the property value" so that information is not lost in parsing would explode the complexity needed for an "interoperable" JSON library.
if someone wants to create some sort of scheme where they do "createdAt$date" as a property name to indicate the value is to be interpreted in some agreed-upon date format, that at least doesn't lose data if the JSON data doesn't understand that scheme, or require a new custom parser in order to properly interpret that data, compared to something like /* $type: date */ "createdAt" :...
This doesn't explode anything and you don't need to lose any data, so the monstrosity of XML still has no benefit, and neither does "createdAt$date", which would need a custom library anyway, so it doesn't matter where you insert your types
If you need additional fields in the json to hold comments, why not add the fields however you want? And if you need meta-data for the parser, you could add it the same way. In a project, i am working on right now, we simply use a attribute called "comment", for comments.
e.g. use "_" as a prefix to mark comments, and then tell you applications to ignore these attributes.
{
"mystring": "string123",
"_mystring": "i am a comment for mystring",
"mynum": 123,
"_mynum": "i am a comment for mynum",
"comment": "i am a comment for the entire object"
}> If you need additional fields in the json to hold comments
I don't need additonal fields, I need comments
> why not add the fields however you want
Because I can't do that either, there are noticeable limitations
That may not be a huge problem for you, you see the "comment" key and know its just a comment and can ignore when a parser treats it like a normal string field. It could be an issue though, for example I could see any code that runs logic against all keys in the object becoming harder to maintain.
You can make special key names that are really directions for something.
You can make enrire k v pairs that are never used by anything that actually parses the json normally.
Argument was invalid as far as I can see and calling it "sorry it makes you sad" is, wow I don't even know where to begin with that.
Having annotation happen in a dedicated place designed for it is better than having it happen where it was not designed to be, end of math problem.
I think roundtrip with comments is not feasible in general. Most code just expects a hashmap, which it edits and then serializes back. You would need some really clever handling for comments to do it.
Syntax errors and erroneous highlighting are not even item 10000 on my list of JSON concerns.
Dare I pull a tired cliche and say “you’re using it wrong”
Trying to prevent programmers from doing something "because they may 'misuse' comments" is asinine to the extreme. This is not like removing a footgun, it's trying to dictate how you think programming should be done. This is particularly hilarious because I've instead seen tons of horribly hacky workarounds for JSON's lack of comments, e.g. "fake" object entries like "__previousKey_comment": "this is a comment for previous key", or even worse, putting two entries with the same key since the second key should "win", and thus making the first entry the comment.
As for his second point, "Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser." - just look at the everlasting shit show that is package.json since it can't support comments, because lots of NPM tools actually write to package.json, so there is no guarantee that other tools will be able to read package.json if it includes comments.
I think the thing that I hate most about Crockford's rationalization of not having comments is that you have to have your head stuck 10 feet in the sand to pretend that somehow the lack of comments is a good thing with the benefit of hindsight. I guess I could understand if Crockford's position was "Yeah, originally I thought it was better to keep them out because I was concerned about misuse, but now in retrospect to see the much larger problems it causes, and I realize it was a mistake." But instead he just keeps pushing his original crappy opinion on this topic.
conf = {};
configFile.split('\n').forEach( function(x){
y = x.split(' ');
if(y[1]=="=") conf[y[0]] = y[2];
});
Everything is a comment with exception of lines like:speed = 100 km/h
weight = 60 kg
maxBuffer = 200 chars (between 100 and 300 works best)
output: {"speed":100,"weight":60,"maxBuffer":200}
It had walls of text with headings and something configurable sprinkled in. Crockford would be screaming. lol
[1] https://en.wikipedia.org/wiki/Whitespace_(programming_langua...
An example I think every Node developer can commiserate with is that there isn't really a great way to add comments in the dependencies or devDependencies section in package.json, because those keys need to refer to module names, and that's where I most often want to use comments in package.json. I won't rehash all the details but just take a look at https://stackoverflow.com/questions/14221579/how-do-i-add-co... . Unfortunately none of the answers there are very good. In the past I've resorted to doing what https://stackoverflow.com/a/45815391/1075909 does, but that ends up not working very well once you've got a long list of dependencies, because the comment for any particular dependency ends up being far from the entry that specifies the dependency (instead of the line above), so people end up not reading it or forget to update it if that becomes necessary.
Yeah, I really, really hate that JSON doesn't have comments :)
They just preserve the key starts with $ for special use
So a class A with a double and and an int field will be something like
{
"$type": "A"
"value":{
"a": {
"$type": "double",
"value": 1
},
"b": {
"$type": "int",
"value": 2
}
}
}
And what about keys that actually starts with $?You just escape it with special $raw key
"$raw": {
"$escaped": {
"$type": "double",
"value" 1
}
}
It's a bit way too verbose. But given it is just a serialization format inside some library or app, it won't cause too much problems.I don't know who @fat is, but if he thinks Crockford's rationalization for the lack of comments in JSON is total and complete BS, I like the way he thinks.
Not sure why all the downvotes? Thought this was a classic.
>Trying to prevent programmers from doing something "because they may 'misuse' comments" is asinine to the extreme.
Programmers are often their own worst enemies. Some prefer rigid rulesets over less rigid freeform programming. See Typescript vs Javascript. No comments in JSON is just another example of over-rigidification, and some programmers love that.
>package.json since it can't support comments,
If you're needing to write comments in package.json, maybe you're not approaching package.json correctly? It's really for node things, not your things that you need to write comments about. I'm not even sure why someone would want to write comments in package.json. I get it with comments in other JSON files, but package.json probably should be left for nodejs things.
1. So what if JSON is primarily used for data interchange? It's not like allowing comments would somehow make them magically show up on serialized objects. This objection makes 0 sense to me. And heck, tons of other serialization formats (e.g. XML) support comments. Besides, there is a big reason that human-readable serialization formats are so popular - because they're human readable! If you're really worried about size you should be using a binary format anyway.
2. "Rigid rulesets" has nothing to do with Crockford's arguments. It's one thing to prefer a particular type system, or limit functionality if you think it has high potential for misuse. By JSON not having comments all you end up with is worse workarounds, like putting comments in object keys.
3. "I'm not even sure why someone would want to write comments in package.json" To be blunt, then, I can't believe you've ever written any code in a business (i.e. with multiple developers) in the Node/NPM ecosystem. Is it really that hard to wonder why someone would want to comment why they added a particular dependency to their project? The lack of comments in package.json is one of the biggest complaints of this format, and it's certainly not just me, e.g. https://github.com/npm/npm/issues/4482 and https://stackoverflow.com/questions/14221579/how-do-i-add-co...
Surely that's what the commit message is for? I mean, I get that it's more convenient to have the comment right there in the file, but that should be balanced against the downsides: having to maintain the comment, making the file larger and more awkward to read, etc.
Yes, I still think a commit message is important, but it absolutely does not take the place of a comment. Suppose you'd like to do something like this:
// DO NOT change to latest version. MUST pin to version 1.2.3 because
// 1.2.4 includes a subtle bug that doesn't work with our version of
// the zed library. We have an open issue on zed, see
// https://github.com/zed/zed/issues/1234.
// Once that is fixed, we can upgrade.
"foobar": "1.2.3"
There is zero chance that comment is going to be seen if its just in a commit message, furthermore you should never depend on git blame showing a particular comment because it's easy for later commits to overwrite it due to simple things like formatting changes, etc. Yes, in that example case there should be tests too, but IMO the primary purpose for comments is to highlight issues and concerns that aren't immediately apparent just by reading the code.I simply cannot think of another file format that is used for configs that doesn't support comments.
I never suggested using a commit message, there are plenty of other ways to document these things and I'll leave that up to the user to figure out.
So now you've written this tome of a comment in package.json. What happens the next time someone installs a package using npm install? package.json gets rewritten, that's what. Your comment will be gone. I suppose you expect npm to somehow use AI to guess at how to rewrite package.json so it can put your comments in the correct places??
And expecting someone to read package.json before updating or installing a library is just as useful as putting it in a commit message. If you really need to be careful about dependency versioning, you better have more safeguards in place than just a comment in package.json.
>I simply cannot think of another file format that is used for configs that doesn't support comments.
I mostly see configs created as .js or .ts files, where comments are allowed. Not package.json. Never package.json, because package.json is guaranteed to be rewritten regularly. But maybe you missed that part of your bootcamp class? Yes, .js files can be used as "config". It's been done in plenty of projects. It isn't the end of the world. JSON also isn't solely used for configs or data that needs comments, in fact the majority of use cases in the world for JSON won't need any comments at all so writing comments in package.json is kind of an edge-case.
>I simply cannot think of another file format that is used for configs that doesn't support comments.
JSON isn't only a config file format. It's primary use is data transfer.
Dude, I think you're lost, in more ways than one. I was directly responding to a comment that stated "Surely that's what the commit message is for?"
For the rest of your comment, at this point I'd rather have an argument with a dining room table. No shit you can't have comments in package.json now, that's the entire reason that issue https://github.com/npm/npm/issues/4482 is unfixable. If JSON supported comments from the beginning, then tooling would have to respect that, just like the bajillion other config file formats that support tooling that updates the config file programmatically.
Well then you and plenty of other people have some wrong ideas about package.json. That isn't surprising.
package.json gets rewritten for all kinds of things, which is not really compatible with adding comments wherever you want. Adding "why this dependency is here" comments may seem like a good idea to add to package.json, but you're kind of missing the point. If you need that level of documentation, trying to shoehorn it into package.json is just the wrong place for it. Soon enough your package.json looks like a graffiti wall.
>To be blunt, then, I can't believe you've ever written any code in a business (i.e. with multiple developers) in the Node/NPM ecosystem.
Then you'll be astonished that I have been working with nodejs for about 14 years professionally. Sure I have wanted to put comments into package.json, but I was naive and now I'm fine not doing that. I haven't wanted to in many years. I document things in other ways and it has served us all very well. YMMV.
So the right place is to make a graffiti out of another place, instead of in the place where people actually declare the dependencies?
I find it bizarre when people believe in one true way of doing things. I mean, you can declare your dependencies how you like, but if others do it differently, then they're clueless?
Either https://en.wikipedia.org/wiki/Learned_helplessness or https://en.wikipedia.org/wiki/Normalization_of_deviance
[1] https://docs.telerik.com/kendo-ui/styles-and-layout/sass-ver...
Sure you can write everything in another file or put the comments in the commit message. But out-of-band comments are more easily missed or lost. If the package.json got rewritten by `npm install` you'd lose the comments. Inconvenient, but that's trivial to fix at commit time.
Your comment doesn't make any sense. You're just pointing out that developers designed data interchange formats as subsets of JSON which explicitly support metadata and comments. This means they are specifying their schemas to support these usecases in a way clients can and do support it. That, if anything, proves right the decision to not support comments because it resulted in better-defined and well-behaving clients.
We get to choose what approach we take. I prefer the "give them the rope they might need" philosophy. If they hang themselves, oh well.
That said, I have yet to see anyone ever say "Oh man, this programming/configuration/data transfer language would be so great, but I wish they hadn't supported comments!" I see the opposite about JSON all the time.
And I don't see this about other features, e.g. Go specifically decided not to support the ternary operator, and while some folks may like that feature, I think more folks really appreciate that with Go there is generally a "standard" way to do things and it doesn't give you a million different ways to essentially do the same thing.
All that needed to be said was, "Using comment programmatically is bad practice. Don't do it."
there's always someone putting actual logic in comments, and when I rule the world, those people are all going to be put on an island by themselves and they're going to have to deal with each other.
https://www2.jwz.org/doc/cddb.html
(Unfortunately, because jwz blocks HN referrals, you can't click on this link, but will need to copy it into the address bar)
It’s not like there isn’t another side to this argument.
This isn't kneecapping something any more than an inventor requiring programmers in a new language use types, or not use types, whichever the inventor deems preferable.
He invented a thing. He declared how the thing is constructed. That's not kneecapping. That's just defining a thing.
JWCC is also what Tailscale call HuJSON, as in "JSON for Humans", which as amusingly also what json5 claims to be.
It has implementations in JavaScript, C#, C++, Go, Java, Lua, PHP, Python, Rust.
On the other hand:
> leadingDecimalPoint: .8675309
This is just lazy. Can we discuss in depth how much time you saved by skipping the “0” in favor of lesser readability?
> andTrailing: 8675309.,
This doesn’t mean anything to me.
On a personal level, I also don't like ending a number with a . because my brain immediately parses it as a sentence ender and it interrupts my reading flow.
It's just not wanting to keep track of more rules. If you've only ever used languages where a leading decimal point is allowed, it's a pain point to suddenly have to remember that it isn't here, and for no obviously intuitive reason.
It's about wanting to avoid unnecessary conceptual friction. Not lazy keyboard usage.
(Heck, your second example uses an extra keystroke. And it's perfectly readable to me, based on the languages I use.)
JSON5 is not.
There's something to be said for being flexible in your inputs when they are non-ambiguous. Particularly when dealing with files written by hand.
There's no virtue in imposing overly strict syntax when it serves no human purpose. That's trying to alter people to fit machines, rather than altering machines to fit people.
Trailing makes it a floating point type instead of an integer
Still… I can be required to put a zero in, read 0.3, and still think “that’s point three”.
Reference: Postel’s Law
I think Postel's law was intended to apply to alternative implementations of machine-level protocols.
That's not to say that I don't agree that it might be better if JSON implementations would allow trailing commas, which is unlikely to lead to semantic ambiguities. That's too late now though, unless a new JSON to rule them all would appear and we would all agree on that new spec.
https://datatracker.ietf.org/doc/html/draft-thomson-postel-w...
https://datatracker.ietf.org/doc/html/rfc9413
I don't think Postel's Law was necessarily a bad idea, in its time and context. However it seems to have fallen into usage as an argument-ender. This RFC is a useful antidote to that.
Is it universally understood? I think it's a US / English thing. In my country I've never seen numbers written in this way and many people would not "parse" it mentally as 0.8675309
How could the parser see it as a string? This is not YAML and JSON5 still requires quotation marks.
YAML[0] supports JSON formatted resources and octothorpe ('#') comments as well. I didn't see anything in the spec specifically allowing for trailing commas however.
Here is an exemplar using the Ruby YAML module:
#!/usr/bin/ruby
require 'yaml'
puts YAML.load(
%/
# YAML is a strict superset of JSON, which
# means supporting octothorpe end-of-line
# comments is supported in JSON formatted
# YAML if and only if the content is multi-line
# formatted as well (like this example).
{
# This is valid YAML!
"foo" : "bar"
}
/
)
0 - https://yaml.org/spec/1.2.2/Use of indentation to denote nesting can sometimes be an anti-feature, too, because while using that the format does not provide a way to make certain that the entire stream has been read (parens balanced). This may lead to problems or even exploits.
Pure JSON is so painful for human consumption though, I willingly choose yaml if it's the only alternative.
JSON5 may indeed be a sweet spot between human-friendliness and lack of nasty surprises.
What is illustrated above is the definition of a specification-compliant YAML resource strictly using JSON constructs + octothorpe end-of-line comments.
Does this usage mitigate the concerns you have identified?
A good parser does not just accept the inputs you find valid, but also rejects inputs you deem invalid. Running a linter that would report or amend all the footgun-wielding features of yaml before parsing is tanamount to running another parser. Then why bother :)
Allowing multiple types of quotes may be an unnecessary feature but it is a clear lesser evil compared to the mountain of footguns that YAML brings with it.
If you don’t enforce it, in the future the “subset of YAML” property might get weaker, especially if someone else is modifying the config.
If you treat config files the same as code, then using a safe subset of YAML is the same as using a safe subset of C. It is theoretically doable, but without extensive safeguards, someone will eventually slip up.
And multi-line strings. You don't always need that, but when you do, it's absence is very painful.
"//key":"this is here so that foo bars", "key":"value",
valid JSON. Most software handles extra propertiesjust fine
Depending what you use JSON for, "Numbers may be IEEE 754 positive infinity, negative infinity, and NaN." could be a huge plus.
I disagree. Human-friendy multiline strings aren't really optional for a serialization format that will inevitably also be used as a config format sometimes because those are the same problem.
Don't get me wrong, the ubiquity of JSON speaks for itself and is the reason to use it. But, to say it has tangible benefits feels very dishonest.
JSON5 is closer to "javascript object notation" than JSON itself. It's partly an update and partly a removal of arbitrary restrictions.
edit: well as this comment thread indicates, the name is pretty confusing for everyone :)
If it didn't originate from that, what else?
Although it doesn't really make sense since most of the stuff they add predates ES5.
When dealing with large YAML files, I find myself frequently popping them into online “YAML to JSON” tools to actually figure out WTF is going on. JSON5 is much easier to read, at least for me.
yq some.yaml -o jsonThat one is likely more relevant than yq since folks in the json ecosystem are far more likely to be familiar with jq's syntax and thus using gojq is "one stop shopping," not to mention that its error handling is light-years beyond jqlang's copy
YAML is a strict superset of JSON, so defining the former in the syntax of the latter is fully supported by the spec. Perhaps not by every YAML library, to be sure, but those which do not are not conformant. From the YAML spec[0]:
The YAML 1.23 specification was published in 2009. Its
primary focus was making YAML a strict superset of JSON.
0 - https://yaml.org/spec/1.2.2/If YAML is a strict superset, wouldn't that mean that YAML must have at least one feature that is not part of JSON? Wouldn't that make it impossible to define all YAML files as valid JSON?
For a feature like references, you'd have to do the annoying thing and duplicate that section of the file.
For a feature like unquoted strings or extra commas, you just quote the strings or remove the commas.
The various YAML features are in between and mostly close to the latter.
Yes. One of the features YAML supports is the widely documented format we are all familiar with.
However, being a "strict superset of JSON" also means a conformant YAML implementation can load a "pure" JSON resource without issue. The converse is not generally possible as JSON cannot express what YAML can, such as octothorpe ('#') comments.
HTH
EDIT: see also https://news.ycombinator.com/context?id=42361994
Where arrays and objects just look too similar (IMO), white space is significant, most strings are unquoted, etc. And personally I find it quite difficult to really understand what’s going on there, at a glance, compared to JSON (or JSON5).
So what? YAML can be trivially mechanically translated between flow and block syntax.
Additionally plugins let you link your prototxt file with the corresponding proto so you can spot errors right away.
That's a big advantage compared to converting to YAML.
[1]: https://en.m.wikipedia.org/wiki/Clojure#Extensible_Data_Nota...
In fact, there doesn't seem to be a spec or standard for it, outside of the de facto standard used by Clojure and the programs in its orbit. I guess nobody's bothered to write a standard, because the people who are already using EDN are doing fine without one, and the people who aren't either don't know what it is or don't see its value.
I too love edn, but unfortunately most other languages lib abandoned (eg. https://github.com/edn-format/edn-dot-net ). Looking around python seems relatively maintained which is great https://github.com/swaroopch/edn_format/issues
{ :name "John Doe"
:age 30
:languages ["English" "Spanish" "French"]
:address {:street "123 Main St" :city "Anytown"} }I used EDN outside of Clojure. The system needed a relatively large amount of config files, and I chose EDN as a better JSON. Looks familiar to everyone, but supports comments - the primary motivation for that choice.
JSON-5 allows a single trailing comma. EDN simply ignores commas. You can have them, trailing or not. But they are really redundant and incur visual noise.
Perhaps EDN can also be improved, but that's a good format. Convenient.
How might you improve EDN?
We already have 5+ replacements that are far more robust(XML, YML) and IMO they are not great replacements for JSON.
Why? Because you can't trust most people with anything more complicated than JSON.
I shutter at some of the SOAP / XML I have seen and whenever you enable something more complicated inevitably someone comes up with a "clever" idea that ruins your day.
I don't think that's the primary reason. JSON is pervasive because it started out being trivially parseable by JavaScript going back to when people just evaluated it, even before browsers had ridiculously high-perfomance safe JSON parsers. All the other formats are still harder to work with from JavaScript.
If not for that, personally I'd advocate TOML, which is incredibly simple.
Comments and all, ironically.
I mean sure, "and all" would frequently include script injections etc, but you can't argue it wasn't more feature rich!
1. Comments 2. Trailing commas
We don't use any other JSON5 features, which are primarily just that numbers may be encoded in hexadecimal and field names may have quotes elided.
We typically encode values with RFC 4648 base 64 URI canonical with padding truncated (b64ut) with values too large to be a JSON number, so hex isn't useful anyway. We haven't found that omitting field name quotes is a big deal.
JSON5, in contrast, has an actual spec that has been stable for 6 years now.
is yaml robust: noExtra hint:
scandinavian countries:
- dk
- no
- se
Edit: it's extremely unlikely a yaml parser implements that spec; the spec is irrelevant.I love JSON, but one of the technical problems we've ran into with JSON is that the spec forgot about all special characters.
I actually noticed it when reading Douglas Crockford's 2018 book, "How JavaScript Works". The mistake is on page 22.9 where it states that there are 32 control characters. There are not 32 control characters. There are 33 7-bit ASCII control characters and 65 Unicode control characters. When thinking in terms of ASCII, everyone always remembers the first 32 and forgets the 33rd, `del`. I then went back and noticed that it was also wrong in the RFC and subsequent revisions. (JSON is defined to be UTF-8 and is thus Unicode.)
Below is a RFC errata report just to point out the error for others.
Errata ID: 7673 Date Reported: 2023-10-11
Section 7 says:
The representation of strings is similar to conventions used in the C family of programming languages. A string begins and ends with quotation marks. All Unicode characters may be placed within the quotation marks, except for the characters that MUST be escaped: quotation mark, reverse solidus, and the control characters (U+0000 through U+001F).
It should say:
The representation of strings is similar to conventions used in the C family of programming languages. A string begins and ends with quotation marks. All Unicode characters may be placed within the quotation marks, except for the characters that MUST be escaped: quotation mark, reverse solidus, and the control characters (U+0000 through U+001F, U+007F, and U+0080 through U+009F).
Notes:
There are 33 7-bit control characters, but the JSON RFC only listed 32 by omitting the inclusion of the last control character in the 7-bit ASCII range, 'del.' However, JSON is not limited to 7-bit ASCII; it is Unicode. Unicode encompasses 65 control characters from U+0080 to U+009F, totaling an additional 32 characters. The section that currently reads "U+0000 through U+001F" should include these additional control characters reading as "U+0000 through U+001F, U+007F, and U+0080 through U+009F"
---
I've chosen `del` to be my favorite control character since so many engineers forget it. Someone needs to remember that poor little guy.
Makes more sense to drop the term "control character" and leave the specification of which characters are not allowed as-is.
The cat's already out of the bag on this one. Changing the characters now will create a lot of invalid JSON in the world, with more being generated all the time.
Once you want to have arrays of nested objects or objects with arrays, I immediately wish I was just reading JSON so I knew where I was in the tree.
And for that reason, I don't think it's a full contender. I want an answer for the hard cases like nested data, not just another way to write the simple cases which is what TOML is.
For example,
[[a.b]]
x = 1
[a]
y = 2
Versus: {
"a": {
"b": [ { "x": 1 } ],
"y": 2
}
}
It's easy to complain that the latter is noisier. But that's nothing compared to being clear. a = { b = [ { x = 1 } ], y = 2 }
(And yes, that can be the entire document; you can have an inline table before the first table header.)Of course, this doesn't help if you want the top level to be an "array" rather than an "object" (in JSON parlance), or if you want the entire document to represent a single primitive value. But these uses are discouraged at best anyway.
But really the goal of TOML is to highlight the location of important parts of the deserialized tree structure (hence the ability to use arbitrary long dotted paths in table headers) rather than the structure itself. It's IMO a beautiful implementation of the idea "flat is better than nested" from the Zen of Python, and it neatly sidesteps an issue I asked about many years ago on Stack Overflow (https://stackoverflow.com/questions/4372229 - the question was rightfully closed, as this sort of discussion doesn't fit the Q&A format; but it made sense to ask at the time).
I don't know if a direct comparison of TOML to YAML is fair. Among other differences, the standard way to parse YAML in Python involves a third-party library that brings in a ~2.5 MB compiled C library. Every TOML implementation I encountered - including the one that made it into the standard library - is pure Python.
To my knowledge, such uses were discouraged only because of a security issue from evaluating a JSON string as a JavaScript code and not via something like JSON.parse.
[a]
b = [{x = 1}]
y = 2
Or alternatively: a.b = [{x = 1}]
a.y = 2
Some parsers allow newlines in TOML inline tables, so you can do: a = {
b = [{x = 1}],
y = 2,
}
That's supposed to be in the next TOML standard, but that seems indefinitely stalled as the (only) maintainer has seemingly lost interest and there hasn't been any movement for a long time.Anecdata, granted, but I've seen a lot of TOML written exactly like the "convoluted" example, and none like your more spread out version.
Yes, that's largely why inline tables and arrays exist:
>>> tomllib.loads("""
... [[outer]]
... first = [1, 2, 3]
... second = [4, 5, 6]
...
... [[outer]]
... third = [7, 8, 9]
... fourth = [10, 11, 12]
... """)
{'outer': [{'first': [1, 2, 3], 'second': [4, 5, 6]}, {'third': [7, 8, 9], 'fourth': [10, 11, 12]}]}All I miss in JSON are comments and a native datetime type. Everything else, I’m fine with.
JavaScript certainly doesn't.
(Reference: https://youtu.be/y8OnoxKotPQ)
Make it raw ISO 8601 { "created_at": 2024-12-10T11:20:07Z } and do not accept any other format. I know there are way smarter people than me who can figure this out at this point.
DateTimes are the number 1 reason I can not use JSON data as is (if I simply parse it into a dynamic object like JSON.parse).
If not, what is the difference, and why was it made to be different?
1. Literal values only (objects, arrays, strings, numerics, booleans, maybe datetimes), a la JSON, with standardized semantics
2. Literals, variable definitions and references, pure function definitions, and pure function calls, but prohibiting recursion, such that evaluation is not Turing-complete and any value is guaranteed to be able to be evaluated into its literal form in finite time
3. All of the above plus recursion and impure, side-effectful functions, custom type definitions, etc.
This way, implementing a literal parser in other languages would be comparatively straightforward (much like JSON), since it wouldn't have to support variables or functions, but it would also be possible to define values using variables and pure functions (much like HCL or Nix) and then use the language's own evaluator binary (or perhaps a wrapped FFI library) to safely convert these into literal values that another language can parse, while guaranteeing that evaluation will not have side-effects. It would also leave open the escape hatch of using a "full" Turing-complete language with side-effects and recursion, while ensuring that using that escape hatch is a deliberate choice and not the default.
I'm sure there are a few additional or hybrid levels that could be useful too (2 but with recursion? 1 but with variables?) but this seems like it would be a solid starting point.
No template literals (backticks)
No regex literals
No octal numbers (0123, 0o123)
No boolean numbers (0b1001)
No big ints (the "n" suffix)
There are many, many more types to support and all this does is complicate syntax; the types can be relegated to a schema. For example, where are dates, with or without timezones, what about durations, what about SI units for mass, current, what about currency, what about the positive integers only, numbers as hex, as octal, as base64...
One format that _nearly_ gets it is NestedText https://nestedtext.org/en/latest/basic_syntax.html ... which means everything gets ingested as strings, dicts or lists, which vastly simplifies things; my quibbles with it would be it still went for multiple syntaxes (for dictionaries, multiline strings, inline vs multiline dicts&lists. And yet, it still didn't make comments part of the data model (which is so useful when processing or refactoring files). While it's not perfect, it does separate the validation of scalars, not stuffing someone's priority list of validations into incomprehensible syntax.
YAML's been a decades long mistake and making JSON more like YAML is not the way to fix that.
I like what apple is doing with https://pkl-lang.org/ though.
- instead of trailing commas, how about making them completely optional? It's not like they are needed in the first place.
- curly braces for top-level objects could be optional too.
- For a data exchange format, there should really be a standard size for numbers, like i32 for integers and f64 for floats.
- parsing an object with duplicate keys is still undefined behavior.
Elasticsearch and Opensearch both actually have partial support for JSON5 (comments), which is a nice feature if you want to document e.g. a complex query or mapping choice. It won't return any comments in the response. So it won't break other parsers. Implementing JSON 5 support like this is a valid thing to do for any server. More broad support for this in parsers would be nice.
I'd probably enable this on my own servers if this was possible. I'd need that to be supported in kotlinx.serialization. See discussion on this here: https://github.com/Kotlin/kotlinx.serialization/issues/797
Do you have a source on that? I am not sure I agree. My gripe is with HOCON that accepts so many formats that after a while you have no idea what it is you are actually writing. You can have a conf file with 5 different formats of the same type of setting. Probably added to by 5 different developers.
I'd rather have it throw an error in my face when I don't adhere.
Of course the hard part is gaining enough critical mass to make a significant switch. JSON had AJAX. YAML had Rails. What could make JSON5 or KDL break out?
[1] See Chapter 3.8 "Surrogates" of the Unicode Standard.
Parsing and converting these strings can be cumbersome because a single Unicode character is often represented by a single escape sequence, but sometimes it requires two.
It means that something you can't tell if it's JSON or another format. You'll have some tools that can work with it, while other tools will choke because they expect valid JSON. Oh, someone just switched the quoting style so now your jq based automation is all broken.
And now you have to figure out which of these not-quite-JSON formats this is. Is it HuJSON/JWCC? Is it JSON5? Does my editor have a mode that supports this particular variant, or am I always going to be fighting with it?
And finally, having used HuJSON for Tailscale config: the issue isn't just things like comments and trailing commas, or quoting styles. JSON is just a kind of heavyweight and cumbersome syntax for writing config files. I find that I prefer writing a script to auto-generate my Tailscale config, because editing it by hand is cumbersome.
There are a number of other possible config file formats, with varying levels of JSON data model compatibility. YAML has its issues, but we've all learned to live with them by now. TOML isn't bad, though good luck remembering the array of tables syntax. KDL is pretty nice; it has a slightly different data model than JSON, but it's actually one that is somewhat better suited for config files.
I'd rather use any of these for config files than something that is almost, but not quite, JSON.
As an (unfortunate) JavaScript developer, it was clear to me the intent was to "update" JSON with ES5 features, and not say ES4 or ES6.
Why ES5? ES5 is when trailing commas were introduced. Commas are one of defining features of JSON5. Other languages, like Go, also made this a priority.
The one thing I really wish it had was some form of multi-line string, mostly so I could use it with line diffs. Also sometimes for really simple property editors it's nice to put the serialization in a textarea, and that works fine for everything but multiline strings.
(I suppose you can escape newline characters to put a string on multiple lines, but I find that rather inhumane and fragile)
I tried to paste in the kitchen sink - it didn't like dangling decimals and the comment format, everything else worked as expected.
What would be the advantages/disadvantages?
If I were doing a professional project, I'd be hesitant to use it over something with more popularity and support. The syntax has so many variations two files can look like two totally different config languages, which is both cool and alarming.
{"foo": "2", "bar": "null", "baz": "false"}
I’m not really being facetious: that’s what canonical s-expressions did: ((foo 2) (bar null) (baz false))Booleans and numbers have extremely common use cases, moreso than date/times.
But perhaps more importantly, they are quite easy to define. Date/time is a susprisingly complex topic with many variants (date, time, datetime, local/relative date/time, point in time, offset-based, timezone-based...) with all of them being quite important. The spec to define date/time types would likely be longer than for the whole rest of JSON, and you still wouldn't be able to correctly interpret the date/time from the spec alone, since timezone data/designations are dynamic.
Now the question is - what value does this extra complexity bring? I'm not saying there isn't any, but it doesn't seem to justify the cost.
Yes, you could represent everything as a string; in that case, the serialization format is no longer providing any assistance in verifying or enforcing syntax.
But it’s often useful to be able to verify syntax independently. And it helps avoid authoring errors (like using “1” instead of “true” etc.) that are ambiguous if your only hint is semantic.
[0]: https://pkl-lang.org
There is a std json library as well but the aesthetics weren’t great imo.
The specs are quite pleasant to implement.
Neither JSON supports JS objects (lack of NaN) nor JS supports JSON (lack of arbitrary precision decimals).
The emoji in the first paragraph seems to convey the understanding that humans like expressiveness, but the format itself doesn't allow Unicode values in keys, which seriously limits said expressiveness...
I honestly cannot imagine hand typing out some JSON now, or most code for that matter.
I just write in natural language what I want and the AI will perfectly output valid JSON.
Oh... and TRAILING COMMAS!
All JSON is valid YAML. So you clearly can make yet another one of these and make it support JSON. But JSON doesn’t support the stuff you’re adding, so calling it JSON5 just makes things confusing as if it’s a version and not a whole new thing altogether.
The ugliest thing the authors could accomplish is making this sufficiently popular that there’s a ton of .json files out there that aren’t actually valid JSON. I hope they’re being careful about strongly discouraging ever writing these outputs to files with a .json filetype.
Yes, this is for situations where the config is two way, e.g. when a GUI can be used to set some values. But I find some of those features so useful that I might sometimes be tempted to write out a processed version of the file parsed even when there isn't anything like a configuration UI.
Then take a look at the JSON spec: https://datatracker.ietf.org/doc/html/rfc7159
1. Add `;` as a separator of elements, so you may have:
{ a: "foo"; b:"bar; }
2. Add array tags and space separated value lists so you may have { a: 12 13 14; }
to be treated as [12, 13, 14] with the tag " ". Normal arrays are parsed with the tag ","
3. Add "functors" as, again, tagged arrays rgb(128,128,14);
will be parsed to an array with the tag "rgb". Also you may have calc(128 + 14);
4. Add tagged numbers so 90deg
will be parsed as a number with the tag "deg"
And you will get pretty much CSS that is proven to define quite complex constructs with minimal syntax.Sorry but what is the benefit of this? Lazy shorthand? This is too much. Is this a string in other languages? PHP the `.` is a string concat.
I agree it would be nice to have something with more data types. Binary b64/hex would be nice.
When you read 847548, is that a number or is that Saturday, 10 January 1970?
Having a type removes that ambiguity. It would be more JSONish for it to be human readable, maybe @1970-01-10T19:25:48.
Mongo types the field name, `{"$date":1623132000}`, if I'm not mistaken. Rust style would be `1623132000_unix`.
Or with anticipation of a more full typing system, where the time is explicitly named:
`{"now": unix:1623132000}`
For now, when I need typing, I use https://json-schema.org
If you need more, you enter territory that is much too complex to build into the "simplest data format" spec.
Every time I learn a new format I want to scream "why can't you be normal?"
until then, jsonc works for me
Another thing is that It feels wrong to have comments in JSON, like allowing comments in CSV files.