I cringe whenever I hear people advocating that it's okay to avoid braces with single-statement conditionals/loops/etc.
This is a perfect example of just how bad that suggestion is, and just how disastrous it can be. It's totally worth typing a few extra characters here and there to basically avoid these kind of situations completely.
I hate omitting braces, but Javascript semicolon omission is a totally different argument. It's easy to show simple cases where omitting braces causes problems. It's actually quite difficult and artificial to find cases where (especially with "use strict") semicolons confer any benefit at all, and in some cases they make things worse (e.g. multi-line variable declarations). Also, "correct" use of semicolons in Javascript makes code less consistent (e.g. some function declarations end with a semicolon, others do not) whereas consistent use of braces is consistent.
I certainly see far more bugs caused by an improperly inserted semicolon than an improperly omitted semicolon, but then I'm looking at jshinted code most of the time.
I used to believe as you do that semicolon issues were contrived and unlikely in JavaScript. But over the years I've been bitten by it enough times to know better.
IIFEs are the most common source of semicolon problems:
for(i = 0; i < 10; i++){
x = arr[i]
(function(x) {
setTimeout(function(){console.log(x)})
})()
}
A less common sort of pattern that I still use pretty often as a DRY measure:
This is clean and readable, and without semicolons it's completely wrong.
Now sure, you can prepend semicolons to these specific cases, and that will work. Here's why I dislike that:
1. Those leading semicolons look weird. To the uninitiated, it looks like a typo, and that's a significant hazard if anyone else is going to touch your code.
2. While there are only a handful of special rules like this to remember, there's only one rule to remember if you don't rely on ASI.
Good examples actually. (Makes me feel better about my ingrained semicolon habit.)
Your examples will crash immediately and at the right spot though. The problems I see caused by excessive use of semicolons are often far weirder.
That said, inadvertent errors caused by semicolon insertion are still more common and baffling (especially by people addicted to jslint who use a variable declaration idiom particularly easy to screw up with errant semicolons).
The first example won't crash if the rvalue preceding the IIFE is a higher-order function (specifically, one that outputs a function).
A relatively rare scenario, but a brutal one to debug.
As for errors caused by extra semicolons, they can be weird, but I don't think I've ever actually hit one in practice. They'd also be a little easier to spot, since you tend to develop a reasonable instinct for where semicolons belong.
I'd say it's a lot easier to be suspicious of lines of code that start with '(' or '[' than find semicolons at the end of the wrong line. It's incredibly easy to put a semicolon where a comma is expected and vice versa. I do it all the time (usually causing an immediate error so it's not a huge deal).
...just overwrote c in a different scope. This kind of bug is common, idiomatic, baffling, and actually more likely among coders subscribing to javascript "best practices".
jslint won't stop it if there's a variable (c in this case) in the outer scope -- it's perfectly fine code as far as jslint is concerned. And jslint encourages that declaration style (actually encourages is too weak a word).
I do write single statement conditionals without braces, but I write them on one line
That's fine until you write
if (something) do_something(); do_something();
or worse:
if (something); do_something();
I've actually seen something very similar to that one.
You haven't really changed the dimensions of the problem by putting it all one one line. Only the whitespace is different. Sure it looks wrong to you; but so does the incorrect code from apple.
I don't understand the need to omit braces; it doesn't make the compiled program any smaller. And denser source code is not always more readable, or we'd prefer "? :" to "if" every time.
This is true; there is no silver bullet. So we rely on defence in depth.
The first line of defence is consistent code layout; e.g. always use "{ }" after an if, and only one statement per line. This aims to make simple typos less likely to compile, make the code more readable and so make errors stand out.
Then there is using and paying attention to the linter / compiler warnings / jshint + 'use strict' / static analysis or whatever it’s called in your language of choice.
Then there are unit tests or integration tests.
Any of these might have caught the apple error, but there are no absolute guarantees.
IMHO it's a professionalism issue – gifted amateurs are great, and they can succeed... most of the time. But a professional engineer would put aside ego "I won’t make mistake like that" and laziness "I don’t need to type braces this time" and do the careful thing every time. Because each step raises the bar, and makes it harder to ship code with bugs like this. Because sometimes it matters.
Comments
I cringe whenever I hear people advocating that it's okay to avoid braces with single-statement conditionals/loops/etc.
This is a perfect example of just how bad that suggestion is, and just how disastrous it can be. It's totally worth typing a few extra characters here and there to basically avoid these kind of situations completely.
Exactly this
This also applies to the "JS without ;" crowd.
You may think you're too good to know all the rules of ; or you can just don't think about it, and worry about other things instead, like your code.
I hate omitting braces, but Javascript semicolon omission is a totally different argument. It's easy to show simple cases where omitting braces causes problems. It's actually quite difficult and artificial to find cases where (especially with "use strict") semicolons confer any benefit at all, and in some cases they make things worse (e.g. multi-line variable declarations). Also, "correct" use of semicolons in Javascript makes code less consistent (e.g. some function declarations end with a semicolon, others do not) whereas consistent use of braces is consistent.
I certainly see far more bugs caused by an improperly inserted semicolon than an improperly omitted semicolon, but then I'm looking at jshinted code most of the time.
I used to believe as you do that semicolon issues were contrived and unlikely in JavaScript. But over the years I've been bitten by it enough times to know better.
IIFEs are the most common source of semicolon problems:
A less common sort of pattern that I still use pretty often as a DRY measure: This is clean and readable, and without semicolons it's completely wrong.Now sure, you can prepend semicolons to these specific cases, and that will work. Here's why I dislike that:
1. Those leading semicolons look weird. To the uninitiated, it looks like a typo, and that's a significant hazard if anyone else is going to touch your code.
2. While there are only a handful of special rules like this to remember, there's only one rule to remember if you don't rely on ASI.
Good examples actually. (Makes me feel better about my ingrained semicolon habit.)
Your examples will crash immediately and at the right spot though. The problems I see caused by excessive use of semicolons are often far weirder.
That said, inadvertent errors caused by semicolon insertion are still more common and baffling (especially by people addicted to jslint who use a variable declaration idiom particularly easy to screw up with errant semicolons).
The first example won't crash if the rvalue preceding the IIFE is a higher-order function (specifically, one that outputs a function).
A relatively rare scenario, but a brutal one to debug.
As for errors caused by extra semicolons, they can be weird, but I don't think I've ever actually hit one in practice. They'd also be a little easier to spot, since you tend to develop a reasonable instinct for where semicolons belong.
I'd say it's a lot easier to be suspicious of lines of code that start with '(' or '[' than find semicolons at the end of the wrong line. It's incredibly easy to put a semicolon where a comma is expected and vice versa. I do it all the time (usually causing an immediate error so it's not a huge deal).
"It's actually quite difficult and artificial to find cases where (especially with "use strict") semicolons confer any benefit at all,"
Hence these are the cases where more time and resources will be wasted because of it.
"I certainly see far more bugs caused by an improperly inserted semicolon"
What would be an example of this? Because I've seen exactly zero bugs of this type (not counting typos, of course)
var a = 17, b = 13; c = 5;
(usually this will be across multiple lines)
...just overwrote c in a different scope. This kind of bug is common, idiomatic, baffling, and actually more likely among coders subscribing to javascript "best practices".
use strict? jshint / jslint your code?
This doesn't justify playing a guessing game and skipping semicolons just because you think you know all the rules about not using them.
jslint won't stop it if there's a variable (c in this case) in the outer scope -- it's perfectly fine code as far as jslint is concerned. And jslint encourages that declaration style (actually encourages is too weak a word).
I do write single statement conditionals without braces, but I write them on one line, which emphasizes the single-statement nature:
Instead of: So it's much less likely that I'll confuse indentation with a block scope.That's fine until you write
or worse: I've actually seen something very similar to that one.You haven't really changed the dimensions of the problem by putting it all one one line. Only the whitespace is different. Sure it looks wrong to you; but so does the incorrect code from apple.
I don't understand the need to omit braces; it doesn't make the compiled program any smaller. And denser source code is not always more readable, or we'd prefer "? :" to "if" every time.
Note that braces won't save you from
(Personally, I configure my editor to highlight if (...); in bright red.)This is true; there is no silver bullet. So we rely on defence in depth.
The first line of defence is consistent code layout; e.g. always use "{ }" after an if, and only one statement per line. This aims to make simple typos less likely to compile, make the code more readable and so make errors stand out.
Then there is using and paying attention to the linter / compiler warnings / jshint + 'use strict' / static analysis or whatever it’s called in your language of choice.
Then there are unit tests or integration tests.
Any of these might have caught the apple error, but there are no absolute guarantees.
IMHO it's a professionalism issue – gifted amateurs are great, and they can succeed... most of the time. But a professional engineer would put aside ego "I won’t make mistake like that" and laziness "I don’t need to type braces this time" and do the careful thing every time. Because each step raises the bar, and makes it harder to ship code with bugs like this. Because sometimes it matters.
well you can also write:
if (something); { do_something(); }
So..
your first example is okay, but for me, I'll do this;
if(something) {do_something();}
Many code editors will easily insert curly brace pairs, so it's really just a single extra key stroke you're saving.
Yes, precisely. It's a real "cowboy coder" tell if you ask me, it just reeks of "it's ok because I won't screw up". We should distrust ourselves.