A modest proposal
happyassassin.net
happyassassin.net
JSON is, unfortunately, used in many places as a configuration language (think package.json). Sometimes you have to comment out a section for some experiment. Many times, you want to explain why you included this or that in the config. Hence comments.
The trailing commas issue is slightly annoying, but an order of magnitude less important IMHO.
JSON works better as a language independent serialization format that is incidentally readable.
It's also kind of messy when you have a lot of multiline strings.
Toml is way better. Yes, multilayered objects in toml are ugly. Don't make your users created multilayered objects for their configuration. That's just a bad UX regardless of the language.
Millions of Python programmers might disagree, not to mention that most programmers using languages with meaningless whitespace (as far as the computer is concerned) still put whitespace in there, because humans.
And it isn't like INI is a great experience, either. Flat configs suck in their own ways.
>And it isn't like INI is a great experience, either. Flat configs suck in their own ways.
Yes, INI isn't great, but people who object to significant whitespace don't object to the "whitespace" part, they object to the "significant" part. That code could not compile or have scope errors because of one extra space or because a space replaced a tab just seems absurd to some people.
This is something about which reasonable people can disagree.
The lack of braces enforces a certain style - something that can be found throughout Python. For example, the lack of multi-line lambda statements.
> braces implied by the negative space
It's easier to think of it in the same way that the compiler does: indent and dedent. Indent? Creating a new scope. Dedent? Exiting the current scope. All of the "constant 4 spaces" and "spaces instead of tabs" simply makes it easier for humans to interpret the indent and dedents visually.
In my experience in writing code in multiple languages: even when using braces you, the coder, still effectively require indentation to visually parse blocks. Yes, copying and pasting code is a touch harder, and most text editors are too lazy to parse for indents and dedents, but the first is mitigated by applying basic DRY principles, the second by installing a python-aware plugin.
I think the significant whitespace is a pragmatism thing. If you're already doing it, do it consistently, if you're already doing it consistently do you really need brackets? The answer is no, and the added bonus is you (and everybody else) is forced to do the whitespace consistently. I'll take a consistently formatted codebase over inconsistencies any day!
Things can change. Push the world forward. Think of little things you can do that make the world of development the world you want to be in.
But of course toml is superior to both because it has comments and no significant white space and the comma at the end of lists is optional.
JSON doesn't have "integers" and "floats", it has "numbers" which are are expressed in decimal scientific notation. There's no guarantee an implementation will let you distinguish what was parsed, and the numerical precision and range of interoperable JSON is undefined.
The bottom line is JSON is a risky proposition for financial or scientific data exchange.
And before you say JSON numbers are de-facto IEEE754 doubles, bare in mind that most JSON implementations can't roundtrip them properly.[0] A symptom of everybody wanting to write a toy implementation.
[0] https://rawgit.com/miloyip/nativejson-benchmark/master/sampl...
TBH, common JSON implementations have their problems too. Integer size and integer/float (de-)serialization tend to be somewhat interesting at times. I've even seen implementations serializing JavaScript objects as JSON (e.g., {foo: 2} instead of {"foo": 2})
TLDR: Basically, in a typical Crockford move, he saw people were using them in a specific way he did not like (to store parsing parameters), so he removed them entirely. I say "typical Crockford" because some of his JS linting rules are gratuitous overkill in my opinion. He also suggests that if you want comments, you should pipe the config file through a minifier that removes them before parsing.
Doesn't seem like that much of a good reason to me, but whatever.
1. https://plus.google.com/+DouglasCrockfordEsq/posts/RK8qyGVaG...
Why not use js for config instead of json? It's your app and your config so if you want it to look like json + comments + trailing comma you can. With so many options for config files like yaml, xml, heck even sqlite it does seem a bit silly how much json is used. Herd mentality.
{ "myComment": "This is a comment!", "realValue": 1 }Crockford probably didn't think it would take off like it did, but with hindsight comments would have been the pragmatic choice IMO.
(ETA: JSON already has problems with canonicalization. Adding comments makes this worse. Are they in or out of the equivalence over JSON terms?)
Also standards change, and professionals use their tools in ways the original creators did not imagine a lot, that doesn't make them clueless. Heck, even JSON is a result of professionals misusing a programming language syntax for a serialization protocol.
Trailing commas have been fine everywhere in JS since IE7 - it's about time all interpreters have this as an option, and preferably on by default.
/me ducks.
Don't duck too much. This kind of config implementation is actually pretty common in some other languages. Clojure, for example. Most configuration files for Clojure programs are written in Clojure, and defended as such.
I also see it frequently done in Python and Ruby, given how simple they make it to dynamically import random files as modules. I've even watched a colleague rant about how they couldn't figure out how to do exactly this in Go.
> YAML may seem ‘simple’ and ‘obvious’ at a glance, but it’s actually not. The YAML spec is 23,449 words; for comparison, TOML is 838 words, JSON is 1,969 words, and XML is 20,603 words.
https://arp242.net/weblog/yaml_probably_not_so_great_after_a...
foo: 80:80
bar: 22:22
baz: 22.22
What's the value of foo? It's the string "80:80". What's the value of baz? The float 22.22 What's the value of bar? The integer 1342.I rest my case about both readability and writability.
I know zero toml (don't even know what toml stands for) but I'm pretty sure you meant the value of bar is the string 22:22 based on foo.
That said, I've never run up against this myself - in the face of potential ambiguity I attempt to be explicit, and surround it in quotes to be explicit string.
TOML itself is going through its own growth pains brought on by a rather sizable spec. For example:
>>> pytoml.loads("foo = 20:20:20")
[...]
pytoml.core.TomlError: <string>(1, 9): msgI've used JSON is some constrained places, I can't imagine writing my own YAML parser, or hacking an existing one into a constrained place (no memory allocation for example).
Secondly, JSON is here and you have to deal with it everyday, so smoothing the work wouldn't hurt.
Finally, if you have to pick a format, take TOML. Less error prone than YAML, faster, and injecting executable code and shooting your in the foot is not part of the standard. The fact that a lot of ini files are valid toml is a nice bonus.
Besides, imagine a world of Java, Javascript, C-like anything, where you would be DISALLOWED to have a semicolon after the last statement in a block. Crazy thought, right?
An other reason it works is that almost everything is an expression in Rust, including things like `if` statements. So for instance you can write:
let message =
if auth_ok() {
"success"
} else if tries < 3 {
"try again"
} else {
"failure"
};
If you add semicolumns after the strings the `if` will always evaluate to nil here.Note that this won't work if one branch returns string an and other returns an integer for instance since the type of "message" must be known at compile time.
It also works well for getter functions and lambdas, for instance:
fn is_empty(&self) -> bool {
self.len == 0
}
or: list.sort_by(|a, b| a.key < b.key);
This way you focus on what's important.I can see where you're coming from though, it's easy to dismiss this feature as a bad idea on paper, especially if you've been traumatized with Javascript's insane handling of semicolumns. In practice however it's a rather useful sugar and so far it's been harmless in my experience. It basically makes the language more lispy.
I just think that using the semicolon to make the function return unit instead is problematic. It would be better to have the type system guide that decision, like in Scala. It would be even better to have an explicit `ignore` function or something (like in OCaml) to signal to the compiler that you really want to ignore the value and you only care about uthe side effect. I mean, why would you ever write just e.g. `a < b;`?
Agree. The idea to attach additional semantics to ; is completely nuts, especially as ; is mandatory in Rust (usually, there are odd corner cases where it is not allowed).
Just get rid of mandatory ; completely and let the type system handle the rest.
I guess you could use significant newlines like python but I never really liked that. I think Rust's compromise is pretty decent.
In particular it's the first time I hear people complaining about it, so far most users (myself included) seem to be praising it. Javascript's handling of semicolon is nuts, I wouldn't say Rust's is.
We have computers they are perfectly able infer them for me.
> Javascript's handling of semicolon is nuts, I wouldn't say Rust's is.
- JavaScript does insane things, as usual. This doesn't mean every implementation of semicolon inference has to be that bad and broken.
- Rust goes the other way by pretending it's still 1990.
There are plenty of languages out there that handle semicolon inference perfectly fine.
(Heck, I even let the IDE show me where the compiler has placed them.)
This makes it easier to write and use generic code for which you don't know the return type (could be `String`, could be `()`), without insisting on special cases for "returns a thing" and "doesn't".
Example: I hold a thing of type `T` and want to let you call a function on it. I can write this generically as
pub trait WithMut<T> {
fn with_mut<R, F: Fn(&mut T)->R>(&mut self, func: F) -> R;
}
and now with one implementation I can deal both with functions that return meaningful values, and "computations" that do some work but return nothing (other than `()`).I upvoted you for your link, but actually the argument that it would be good because people who care more will make a better decision than those who don't does not completely convince me. Someone could care a lot about something but still have the wrong idea about it.
Groups frequently make collective decisions through majority rule. Legislators pass bills by majority; shareholders make most corporate decisions by (share-weighted) majority rule, as do directors; clubs, university faculties, and civic associations typically use majority rule as well. The reason that they do so is not entirely clear. (Emphasis mine).
Not clear? It's almost too clear as to be tautological.
They do because they (a) think all members should have equal say, (b) most members in the group want X to be done.
Unless we're talking about submitting to force or listening to expertise, why would many people wanting to do something, let fewer people tell them what to do instead?
Heck, if it comes to fighting for what's to be done (the most effective but primitive form of getting a decision), the majority could beat up the minority and have its way anyway.
What I imagine QV does is find the point at which participants who don't care so much would rather pocket the funds and walk away, rather than spend it on voting.
If the ballot measure is "Eat Vinnl", you might want to spend a lot to vote it down, but it might not take much to convince the others not to spend it back at you (and you all eat berries instead). If the ballot measure is "Vinnl eats everyone else", you won't be able to spend enough that everyone else can't just spend it back at you, more efficiently.
Edit: one important difference here is that unless the GP is actually going to pony up real money, something of value to those they inconvenience with their (imo silly) opinion, it doesn't make much sense.
Anyway, I see it's been submitted separately :) https://news.ycombinator.com/item?id=15206291
it just makes obvious that "result of something" and "control flow back to caller" are very different things.
function square(const x : Integer) : Integer;
begin
result := x * x;
end;
Is equivalent to: function square(const x : Integer) : Integer;
begin
result := x * x
end;
If you mean in if-then-else constructions, then yes the semicolon must be at the end of the statement: if (condition) then
dosomething
else
dosomethingelse;(I'm ignoring the comma operator, which is a special case and not relevant to the main point.)
foo(x, -y)
is not the same as foo(x -y)
(from your last sentence, I assume you were talking about JS in general, not just JSON)Never mind.
Actually, let's double down: Instead of writing 1+2, you should really be writing +(1 2). Don't you see how much easier that would make things? A single, uniform syntax everywhere! + is just a function that gets called like anything else! Your foo(x -y) example would become foo(x -(y)).
I'm mostly joking.
Does use commas for lists and tuples, though. The latter kind-of make sense, it's the commas that identify the expression as a tuple. Not sure what the rationale for commas in lists is, though.
[1] Slightly complicated by currying (arguably, it's several successive function applications rather than one multi-arg application) but the end result is the same...
Well, you need some separator, and spaces won't do since [x y] has x applied to y.
Although could, in principle, make space-between-list-items higher precedence than function application. E.g.:
[x (func y) z] res = -x ==> negative x
res = c - x ==> c minus x
res = - x ==> syntax error foo(x -y) => foo(x, -y)
foo(x - y) => foo(x - y)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
(1) where nobody = limit(somebody) -> 0
Yes, I think they do.
The author just borrowed the title of Swift's article in the sense "here's a fun title based on a historical reference, for something that, for once, it's indeed a modest proposal".
They didn't intend it in the exact same way Swift intended it.
When I was a kid in the 80s, the parents of a kid in my older brother's class complained angrily to the school about this, clearly having failed to realise it was satire.
Here's an excerpt:
"I have been assured by a very knowing American of my acquaintance in London, that a young healthy child well nursed, is, at a year old, a most delicious nourishing and wholesome food, whether stewed, roasted, baked, or boiled; and I make no doubt that it will equally serve in a fricasie, or a ragoust."
You want to preserve the history of your code and to be able to easily query your VC system about the providence of each line of code. I want to add a new item to the end of the list, I also need to add a comma to the end of the previous line. This makes my commit larger than needed and it muddies the code history.
Just let me make simple incremental additions to a file as it changes.
When producing JSON for others, I just use the minimal consensus format (read: the "official" spec).
There are several fundamental problems with JSON, one of which being that you have to duplicate the field names over and over again. It's just not a very structured format. Trailing commas is the least of my concerns.
I would like to see protobuf take over at this point.
You can't edit a protobufs in an editor.
There's a canonical JSON serialisation in v3 as well, although obviously that doesn't solve the OP's problem...
[1] RFC-7049, also http://cbor.io/
[2] http://cbor.schmorp.de/stringref It won't make much sense unless you already understand CBOR encoding, but it's a registered extension.
As a storage format I don't like it, either. No canonical representation (at all): Arbitrary whitespace, arbitrary order of members. Too much line noise: Quotes around each member name. No schema support.
You'd be surprised -- if you had to live through the XML madness of the early 00s. And don't get me started on SOAP, XML namespaces and other crap.
>There are several fundamental problems with JSON, one of which being that you have to duplicate the field names over and over again.
You don't duplicate field names. You define different objects that just happen to have the same fields. They could just as well have different ones.
That's something for transport compression to handle.
{
'fields': ['a', 'b'],
'values': [
[1, 2],
[5, true]
]
} {
a: [1, 2],
b: [5, true],
}
But this doesn't solve the problem if your data isn't a nice table and has deeply nested tree structures. Which is what JSON is for, otherwise people would have just stuck with CSV.Going further with this, I wish languages would be more copy/paste friendly. For example, in JavaScript I'll sometimes change code along the lines of
a.x = 1;
a.y = 2;
to a = {
x: 1,
y: 2
};"
If you eliminate the commas, semicolons and changed the colons/equals to the same thing, you could copy/paste it with much less hassle.You still get errors caused by mis-indented statements which are almost just as hard to check (if the indent continues for 10-15 lines and is nested etc).
And because of allowing to mix tabs and spaces, you also get other issues.
I think go had the best idea in this with gofmt: all code should be auto-formatted absolutely the same -- then it becomes trivial to read.
I find wrong indents miles easier to see than unbalanced brackets/braces though. A single bracket/brace is only one symbol so it's hard to spot but it completely changes the semantics (see Apple's goto fail error).
> I think go had the best idea in this with gofmt: all code should be auto-formatted absolutely the same -- then it becomes trivial to read.
Yes, I like this. There's so many pointless arguments about things to do with naming conventions and tabs vs spaces...just make it part of the language so people can argue about more important topics.
Had braces been used, the error might have been easier to spot or might not have happened at all.
Code has to be correct in ways whitespace doesn't. Some people use tabs, some people use spaces. Some people even use both. In terms of whitespace, it doesn't really matter.
But, if your language cares which of the visually indistinguishable but otherwise incompatible kinds of non-printing characters you're formatting your code with, then it can still fail while visually communicating the correct information to the reader.
How is it not though? For every mainstream language it's standard convention to indent conditions and functions.
> But, if your language cares which of the visually indistinguishable but otherwise incompatible kinds of non-printing characters you're formatting your code with, then it can still fail while visually communicating the correct information to the reader.
This a complete non-issue to me. The pros of significant whitespace vastly overshadow any possible benefit of letting people choose tabs vs spaces and the latter issue is easily solved with IDEs anyway. I don't see people having any issues with this using Python either.
Personally, I think even naming conventions should be enforced by the language as well so people can stop wasting time debating insignificant details and in code reviews.
In Python's case it's not just an aesthetic -- the whitespace is also functional, so that mistake can't happen just for aesthetics.
a.(
x = 1;
y = 2;
)I dunno, that kind of exists in some bash/scripting contexts (using a backslash) and I've never enjoyed it.
Now, I don't know whether commas allow for faster parsers in some way, but edn[1] seems to be doing just fine without them.
Once you get used to optional commas, it really becomes a nuisance having to type them, especially in basic data type lists. The only place where I find commas visually helpful is C-style argument lists (with type and value pairs), which JSON doesn't even use.
A while ago I saw somebody who had implemented pretty much that: a streaming non-validating JSON parser which just ignored commas and colons entirely.
Allowing single quotes would be good too. This makes quoting strings that contain double quotes nicer.
I also experimented with specification of transformations to/from hierarchical representations, but I think the problem is that there are different possible approaches with their own pros and cons.
http://jstimpfle.de/projects/wsl/main.html
http://jstimpfle.de/projects/python-wsl/main.html
Tell me what you think!
I agree, trailing comma's and the lack of comments is extremely annoying in JSON. However, I think the underlying problem is tools using a serialization format for configuration to be the real problem here.
That AWS CloudFormation has added support for YAML is a great example of this and it's a great step forward. I think other tools should follow.
When generating code, it is so wonderful to not have to have the logic to track the first or last object ....
Couldn't git take this into account to visually "depollute" diffs ?
On a related note I'd rather not have any commas like in EDN. All problems go away.
That's a personal opinion -- like a mild OCD annoyance, etc, most like borne just out of being used to not having them from the start.
Their benefits on the other hand (uniform syntax, easier insertions/deletions, better for source code control, etc) are objective.
And there's no objective visual annoyance when looking at the code to see that it's uniformly comma-ed.
I take it you didn't read my original comment?
Also I disagree, dangling comma is a visual cue that the sequence has a continuation.
We already have a mechanism for telling whether a sequence ends or not -- the opening and closing bracket for the sequence. No need to have a second redundant one.
This way the last element is an ordinary part of the sequence as any other and doesn't need a special exception to its formatting like the omission of the comma.
Besides the point is moot as the "dangling" comma is already part of the JS standard.
IMO there is no reason to have commas at all so this discussion is pointless.
In what way is ] also not a visual cue?
Not on modern JS world, which allows for dangling , everywhere: http://2ality.com/2013/07/trailing-commas.html, so having a "," doesn't mean the line is not the last one anymore, just means "it's a line like any other".
It's time JSON gets up with the times -- especially since it's a totally backwards compatible improvement.
yeah, in other words - there should be no commas whatsoever. Weren't you the one complaining about redundancy?