-
-
Save isaacs/357981 to your computer and use it in GitHub Desktop.
// See comments below. | |
// This code sample and justification brought to you by | |
// Isaac Z. Schlueter, aka isaacs | |
// standard style | |
var a = "ape", | |
b = "bat", | |
c = "cat", | |
d = "dog", | |
e = "elf", | |
f = "fly", | |
g = "gnu", | |
h = "hat", | |
i = "ibu"; | |
// comma-first style | |
var a = "ape" | |
, b = "bat" | |
, c = "cat" | |
, d = "dog" | |
, e = "elf" | |
, f = "fly" | |
, g = "gnu" | |
, h = "hat" | |
, i = "ibu" | |
; | |
// error in standard style | |
var a = "ape", | |
b = "bat", | |
c = "cat", | |
d = "dog" | |
e = "elf", | |
f = "fly", | |
g = "gnu", | |
h = "hat", | |
i = "ibu"; | |
// error in comma-first style | |
var a = "ape" | |
, b = "bat" | |
, c = "cat" | |
, d = "dog" | |
e = "elf" | |
, f = "fly" | |
, g = "gnu" | |
, h = "hat" | |
, i = "ibu" | |
; | |
// Objects: | |
// JSON.stringify style | |
var o = { | |
a : "ape", | |
b : "bat", | |
c : "cat", | |
d : "dog", | |
e : "elf", | |
f : "fly", | |
g : "gnu", | |
h : "hat", | |
i : "ibu" | |
}, | |
a = [ | |
[ "ape", "bat" ], | |
[ "cat", "dog" ], | |
[ "elf", "fly" ], | |
[ "gnu", "hat" ], | |
[ "ibu" ] | |
]; | |
// comma-first | |
var o = | |
{ a : "ape" | |
, b : "bat" | |
, c : "cat" | |
, d : "dog" | |
, e : "elf" | |
, f : "fly" | |
, g : "gnu" | |
, h : "hat" | |
, i : "ibu" | |
} | |
, a = | |
[ [ "ape", "bat" ] | |
, [ "cat", "dog" ] | |
, [ "elf", "fly" ] | |
, [ "gnu", "hat" ] | |
, [ "ibu" ] | |
]; | |
// errors in objects: | |
// JSON.stringify style | |
var o = { | |
a : "ape", | |
b : "bat", | |
c : "cat", | |
d : "dog" | |
e : "elf", | |
f : "fly", | |
g : "gnu", | |
h : "hat", | |
i : "ibu" | |
}, | |
a = [ | |
[ "ape", "bat" ], | |
[ "cat", "dog" ], | |
[ "elf", "fly" ] | |
[ "gnu", "hat" ], | |
[ "ibu" ] | |
]; | |
// comma-first | |
var o = | |
{ a : "ape" | |
, b : "bat" | |
, c : "cat" | |
, d : "dog" | |
e : "elf" | |
, f : "fly" | |
, g : "gnu" | |
, h : "hat" | |
, i : "ibu" | |
} | |
, a = | |
[ [ "ape", "bat" ] | |
, [ "cat", "dog" ] | |
, [ "elf", "fly" ] | |
[ "gnu", "hat" ] | |
, [ "ibu" ] | |
]; | |
// Addendum: effects on the return statement. | |
// It does not break. | |
return [ 1 | |
, 2 | |
, 3 | |
] // returns [1,2,3] | |
return { a : "ape" | |
, b : "bat" | |
} // returns {a:"ape",b:"bat"} | |
// even just separating two values by commas is fine, | |
// though a bit silly | |
return 1 | |
, 2 | |
, 3 | |
, 4 // returns the last value, 4 | |
// this, however is wrong: | |
return | |
1 | |
, 2 // returns undefined, because of semicolon-insertion. | |
// so is this. otb == fail. | |
return | |
{ a : "ape" | |
, b : "bat" | |
} // returns undefined, | |
// then creates a block with two named statements. | |
// this is ok: | |
return ( 1 | |
, 2 | |
) // returns 2 | |
// so is this: | |
return ( | |
{ a : "ape" | |
, b : "bat" | |
} | |
) // returns {a:"ape",b:"bat"} | |
// Addendum 2: A function call | |
doSomething( aPrettyLongVariableName | |
, "A string, which has some useful information" | |
, "If you put these all together, it'd be too long" | |
, { a: "is for antelope", b: "is for bat" } | |
, 42 | |
) | |
// Addendum 3: More realistic error in standard style: | |
// leaks FIVE globals! | |
var a = "ape eat banana", | |
b = "bat, allowed to fly", | |
c = "cat toy", | |
d = "dog chasing the mailman," | |
e = "elf lord", | |
f = "fly through the air", | |
g = "gnu is not unix", | |
h = "hat goes on your head", | |
i = "ibu isn't a cow"; | |
// Error: Can't call method 'forEach' of undefined. | |
// not passing in undefined as an argument!?? | |
mergeLists([ apple, [ penelope, granger ] ], | |
[ fun ], | |
[ 1, 2, 3, 4, 5, 6, 7, 8 ] | |
[ "mary's store has many pies, and cookies, and eggs," ] | |
[ function() { doSomething() } ]); |
Why discuss it (at length)?
Three reasons.
- Death by a thousand papercuts.
Its easy to overlook small, mostly-insignificant things.
But as time goes on, they build up, entire ecosystems begin to devote themselves to "solutions" to paper over them (ever seen a system library whose point is to resolve path character differences? There are just two that I know about, but arguably hundreds of lines of code that "fix" this issue). Or, there are many, many small things, so while you have one fix for one thing, now you have 1000 fixes for 1000 things. This is not a sustainable solution, better to actually solve problems than simply work around them.
Now, of course, you perform triage - of those 1000 issues, which are the biggest/most impactful? Fix those first. But, this is an issue that likely covers millions of lines of code, already, the impact is actually bigger than it appears.
- Correctness and graceful degradation.
This is relatively small issue for the user - and today we have some nice tools that (mostly) obviate the need to care too much about this. I don't entirely begrudge you your reading preference, although I do think its largely silly and not something you are probably often doing.
But the two objective reasons to never use comma-last, are:
- Line diffing tools - git etc. display more noise. As said, you could write more code to paper over this issue, and then deal with all bugs/edge-cases/special unforeseen problems.
- Parsing (human and tool). Again, a situation where what you want is
<record><record-separator><record>
, and what you have is<record><carriage-return?><line-feed><record-separator><record>
. Obviously not impossible to work around, but splitting on record separators is both faster and simpler. And for the human eye, unless we start all right-aligning our code (different discussion/issue), we want to see there are 3 records, not that there are 3 lines. One line can be off to the right, and the next line may be a continuation, or the line can contain two records, you may not be able to auto-format due to line length, etc. Screen size is not an acceptable solution either, if you have hundreds of files or windows open, you can't rely on your super big monitor (another case of code, in this case hardware, being built to solve a seemingly small problem) either.
This is the portion of tech debt.
The format you get to see, sure, our editors can be smart. I'm not saying that's a bad thing. But when your editor dies (corrupted, disk lost, copilot subscription link gone, etc), one format remains simply legible, with something simple like "split" command, or as a basic text file (think Notepad or ed level).
So no, I don't think its appropriate or helpful to look at the year and go "lol in 2024, with these tools". That's an nonconstructive, small-minded attitude.
- Love letter to the future
I'm not crazy - I don't believe we'll fix this any time soon, probably not in my lifetime nor in a couple generations.
Now, is it useful to have this discussion here, on github comments, probably not (that's probably up to github to decide how they want to handle longevity). But hopefully someone or something will mirror this discussion, and maybe, someone in the future will be like "hey, yeah, the way we do things is kinda stupid, lets fix it!"
Here's to fixes in the future.
But hopefully someone or something will mirror this discussion, and maybe, someone in the future will be like "hey, yeah, the way we do things is kinda stupid, lets fix it!"
I am an American. We use the imperial measurement system, drive on the right side of the road, overpay for objectively bad health care, force people to live on the street rather than build houses, value our guns more than our children, and treat any attempt at public health protection as the worst form of oppression.
So, idk, I'm kind of cynical. "Objectively better" isn't just not a compelling reason to do anything, by all observations, it seems to be negatively correlated with what we actually do.
@isaacs Cynicism isn't bad, but this goes back to societies... they can and do change, and not always for the better.
I think its important not to be cynical in your approach, even if you are cynical in your outlook. Someone has to advocate for things getting better... or you'll just slide into decay and eventual collapse. Some might argue that's where the USA has been headed, so who knows? A lot can happen in a thousand years, even 100. Who knew the British Empire was on the verge of collapse at the turn of the 19th century?
Anyways I think you stopped talking about commas a while ago and we have devolved into politics. I will bow out of this part of the discussion. :)
OMG. What a fun read.
@isaacs, @Potherca, @smaudet, @Mcfloy, @fischerflorian @happyteque, @KoJaMan, @waynebloss, @alanosman, @sophana, @bhubr, @alystair
I personally think you are all awsome. As awsome as humanly can be.
Did you know?
~99% chance that the keyboard in front of you is not optimal. Because 99% of the keyboards use the QUERTY layout.
There are keyboard layouts that make typing superiorly faster. And that's true for physical keyboard and touch screens.
But they are adopted by less than 1% of the population - at least in my circles (google dvorak or colemak to learn more).
Commas
An important distinction between keyboard layout and code style is that I don't want anybody else sitting on my keyboard, but I do want people to collaborate with me in my code.
I said before - I'm a comma-1st fan, I think it looks like a bullet list, it solves the trailing-comma debate better than anything we had to make the language put up with, and many more reasons. And I know I'm the minority in that.
Over the years the only practical case against it is - when you copy snippets of it to the REPL the shell does not expect another line and breaks. You have to wrap it with {} or something to force the REPL wait. But then again. REPL users are also a minority.
The discussion started when auto-format was in its infancy. Now, autoformat is prevalent.
The point of all this...
At least for me - this was a fun read. This discussion does stimulate some aesthetic urge in my brain, and I can see that for other people as well.
Certainly, tooling changed the scene. A lot.
What used to be an advantageous sharp edge of mine - a keen eye for formatting and reflexes around styling that aid human proofing - has become a liability. I had to adapt.
But still...
The Future
On one side, one can claim that now that we have strong autoformatters and linters we don't need to meticulously not-for-get-a-comma.
On the other hand - fixing all the commas in your codebase is changing a rule and running your formatter...
Well. We could go "woke", and explain to everybody why "coma last" hurts our feelings because it is discriminatory, or bigot, or racist, or something, and tie it to the war in Ukraine and/or Gaza, ... or explain why formatters are facists tools of the kremlin design to deprive you of creativity, yea. Good luck with that. Whoo.. <...shivers> 🤦♂️ (I actually shocked myself. How's that for scynisicm, @isaacs ?)
. . .
So I don't know. Maybe we'll hear more of this.
Until then, stay awsome, stay human, and be respectful.
Evidently, this is also a styling rule that makes things more readable... 😜
I joined this conversation hoping to discover a compelling reason to use trailing commas in code. While I haven't found one yet, I appreciate @osher's summary.
@waynebloss I believe there's at least 1 good reason we need a separator in code and that is to be able to separate items without being forced to place those items on a new line.
Me and my team will continue using comma first. In my opinion we use tools like formatters, linters etc to make code more readable and more manageable and not just to format in a standard manner.
On a separate note, I've observed that sometimes in technical discussions, those who disagree might resort to ridicule instead of providing constructive arguments.
And finally: I fully agree with @osher:
"...stay awesome, stay human, and be respectful.
Evidently, this is also a styling rule that makes things more readable... 😜"
Reading back the comment, my current favorite is:
As in 2024, GitHub Co-Pilot does precisely that. How far we have come... 🥲