I was reading “Delimiter-first code [1]” (via Lobsters [2]) and I was struck by his first example of comma-first formatting:
-- leading commas SELECT employee_name , company_name , salary , state_code , city FROM `employees`
That doesn't look half bad, I thought. It could make for smaller diffs in some cases. For instance, I have this:
fprintf( stdout, "Status: %d\r\n" "X-Error: %s\r\n" "Content-type: text/html\r\n" "\r\n", level, errmsg );
Rework it to use comma-first formatting:
fprintf( stdout , "Status: %d\r\n" "X-Error: %s\r\n" "Content-type: text/html\r\n" "\r\n" , level , errmsg );
I still have to work within the confines of C, but here it's easier to see that the string literal is one long literal and not four additional parameters, so that's good. It's a bit strange looking, but I could get used to it (I got used to “char const” over “const char” because const applies to the object to its right, except if starts the declaration; it makes parsing “char const *const p” easier for me—this declares p to be a constant pointer to constant data). And if I need to add to it:
fprintf( stdout , "Status: %d\r\n" "X-Error: %s\r\n" "Content-type: text/html\r\n" "X-Foobar: %s\r\n" "\r\n" , level , errmsg , foobar );
the diff is easier to follow—this:
5a6 > "X-Foobar: %s\r\n" 8a10 > , foobar
instead of:
5a6 > "X-Foobar: %s\r\n" 8c9,10 < errmsg --- > errmsg, > foobar
But then I came across this bit of code I wrote:
XEvent se = { .xselection = { .type = SelectionNotify, .serial = NextRequest(event->xselectionrequest.display), .send_event = True, .display = event->xselectionrequest.display, .requestor = event->xselectionrequest.requestor, .selection = event->xselectionrequest.selection, .target = event->xselectionrequest.target, .property = event->xselectionrequest.property, .time = event->xselectionrequest.time, } };
And … um …
XEvent se = { .xselection = { .type = SelectionNotify , .serial = NextRequest(event->xselectionrequest.display) , .send_event = True , .display = event->xselectionrequest.display , .requestor = event->xselectionrequest.requestor , .selection = event->xselectionrequest.selection , .target = event->xselectionrequest.target , .property = event->xselectionrequest.property , .time = event->xselectionrequest.time } };
Yeah …
C99 has designated initializers and also allows trailing commas when initializing structures, so the need for comma-first formatting doesn't really apply here; comma-first formatting only really applies to function calls. Perhaps languages should allow trailing commas in all contexts? It's something to think about.
The rest of the article is really about marking items in a list with some delimiter, usually a comma that comes after an item (except for the last item). There's one example he brings up: “1 , 2 , 3” vs. “・1 ・2 ・3” and here, I would say maybe “1 2 3” is best? Using spaces instead of a comma could still work in a lot of contexts in C:
/* none of this is valid C code */ rc = cgi_error(blog req HTTP_BADREQ "bad request"); fprintf( stdout "Status: %s\r\nContent-type: text/html\r\n\r\n" status ); generic_cb("main" stdout callback_init(&cbd blog req));
It only breaks down when we go back to my first example above:
/* still not valid C code */ fprintf( stdout "Status: %d\r\n" "X-Error: %s\r\n" "Content-type: text/html\r\n" "\r\n" level errmsg );
Consecutive string literals are collected together into a single string literal, so such a construct as above could lead to some confusion. But this is just me riffing on using space as a delimiter.
The rest of the article does lay out a decent argument for leading delimiters for a lot of contexts, but removing closing brackets I think is too far. It works for Python because of syntactic white space, but it won't work for nearly any other language. It also fails for languages that support variadic functions [3], so it's probably best to keep both opening and closing brackets (or parenthesis or whatever). It also seems the arguments are more for vertical than horizontal formatting.
The article ends with:
Don’t be too surprised if this proposal evokes “hey this looks wrong, just plain wrong” reaction. After all, ideas we enjoy these days: enumeration from zero, using registers in names, structural programming, mandatory formatting, and even python’s approach to defining code blocks with indentation — every single one of them were met with a storm of criticism.
I'll keep that in mind, but even so, not everyone buys into mandatory formatting or significant white space.
[1] https://arogozhnikov.github.io/2022/11/29/delimiter-comes-first.html
[2] https://lobste.rs/s/9q8rx2/delimiter_first_code