The convenience it offers for diffing is just a manifestation of the positive interaction with grammars and language tools. The convention of humans using trailing commas in lists, along with one item per line, is relatively new, though. Stylistically, this used to be frowned upon as long definition lists made source files longer, slower to scroll through, and worsened code locality from the perspective of someone using, e.g., a 25 row terminal.
I prefer leading commas to having a final comma with an empty clause, though some people hate that and they don't really solve all the final-entry issues (they address some of them, but others are just moved to being first-entry issues).
I've been recently using dyff [0] to diff YAMLs in an order invariant way, and it's been absolutely liberating. Couldn't help with version control, but it's still night and day.
[ "or"
, "alternatively"
, [ "the"
, "first"
, "item"
]
, "could"
, "behave"
, "differently"
]
I feel that, despite its repugnant appearance, this "comma-first" approach is the best tradeoff in languages like JSON where trailing commas are forbidden; the leading `[` is much harder to accidentally omit or insert than the subtle trailing `,`. In Emacs I use js3-mode, a hack of js2-mode to support comma-first syntax.Comma-first syntax is especially convenient in SQL, which has the forbidden-trailing-comma problem and several analogous problems. In C if I have a long Boolean conjunction
if (unpleasantly long boolean expression &&
another unpleasantly long boolean expression &&
yet another unpleasantly long boolean expression) {
there are several ways to fix it, such as nesting ifs or factoring the expressions into variables or functions. The "comma-first" approach is also visually unappealing for spacing reasons, requiring two extra spaces after the parenthesis: if ( unpleasantly long boolean expression
&& another unpleasantly long boolean expression
&& yet another unpleasantly long boolean expression
) {
In SQL, C's alternative approaches are not available, and the "comma-first" style is much more natural: where unpleasantly long boolean expression
and another unpleasantly long boolean expression
and yet another unpleasantly long boolean expression
I do agree, though, that it's better to design languages to avoid this problem, and I think the way to do that is by using item terminators or item initiators in a list rather than by using item separators. That's what C did for statements with `;`, which was a difference from the ALGOL tradition including Pascal, where `;` was a statement separator, with the unpleasant consequences described in https://www.cs.virginia.edu/~evans/cs655/readings/bwk-on-pas....In Meta5ix http://www.canonical.org/~kragen/sw/dev3/meta5ixrun.py I experimented with using item initiators for rules in a grammar, like Markdown uses for bulleted lists. I'm not pleased with the rest of the syntactic decisions I tried in Meta5ix, but I do think that one was a good tradeoff; here's about a quarter of the Meta5ix compiler:
- terms: term ["," {continue $choice} term] @choice
- term: (factor {else $seq}, output) [factor {assert}, output] @seq
- factor: string {literal $it}
, "(" terms ")"
, "[" @many terms {continue $many} "]"
Note that, while comma-first layout feels like a gross abuse of a punctuation mark with `,`, it's quite common and natural with `|` in grammars and pattern-matches in languages like ML, where an initial `|` is also permitted; here's an excerpt from my port of μKanren to OCaml (http://canonical.org/~kragen/sw/dev3/mukanren.ml): let rec walk (s : env) = function
| Vart (Var x) when Env.mem x s -> walk s (Env.find x s)
| u -> u
I think that's what I should have used in Meta5ix, and I will if I get around to revising it.FWIW with SQL multi-line booleans, I tend to do:
WHERE TRUE
AND something
AND something_else