Can You Find the Bug in This Code?
victorzhou.com
victorzhou.com
"Is the language specification too loose?"
"No, it's the developers who are wrong."
The explanations that have been given to me typically fall in line with, "well, to new comers, it won't make sense why you don't add a semicolon after a function declaration or if statement. I consider that a teaching moment.
But, I'll admit, this debate has little merit. Folks whom are dead set against using them are rarely convinced until they get bitten hard by a 2 hour hunt for an obscure bug. And folks that use them will probably end up with RSI or Emacs Pinky™
Honestly -- then they'll never be convinced. I haven't hit an ASI bug in the last decade.
I think abusing ASI is a funny hack (and I did it for a while) but the more functional my programming style became the more ran into these cases, so I channeled my inner Douglas Crockford and reopened my bag of semicolons.
;['but', 'why']
.reduce((msg, word) =>
msg + word,
''
).join(' ') +'?'There are a number of cases where not having semicolons has its downsides, I'm yet to see a single case of an upside.
It's a signal of coolness from inexperienced programmers. That's the value proposition offered by semicolon-free JS.
So, sorry but you couldn't possibly be more wrong. The great majority of the other commenters here disagree with you as well. You got lucky if you have in fact never had an ASI bug as you claim, but in this thread there is at least one link to a famous bug that has been caused by it and mention of others. The fact that you anecdotally gambled and "won" doesn't hold a lot of weight.
There is one much less popular style guide which actually made headlines for recommending against semi-colons and they got roundly criticized for it by many, many famous JS programmers including the likes of Dan Abramov from Facebook. The author of this style guide tried to weasel more popularity out of it by calling his guide "Standard" since he knows for a fact that the vast majority of JS coders use a de facto style that includes semi-colons. That's exactly the type of behavior that I expect from young, inexperienced coders who make poor decisions based on vanity. I see it all day long from junior programmers. Luckily for everyone in my company, it's my job to set them straight.
I'm sure they love being told they're wrong because they're young and vain.
I'm aware styleguides recommend semis but I'm more referring to people who have strong opinions about what is a minor semantic. For my part it's simple: the effort involved using semicolons correctly (and in my experience many devs who like semis use them inconsistently) is significantly greater than the effort to fix/prevent ASI bugs. The only possible caveat to this is if you're using a code-formatter like Prettier to handle semis for you -- but then Prettier will catch and fix ASI bugs for you even if you don't.
I wouldn't say that, but it is a decision based on vanity and it does tend to come from younger/junior coders in my experience. Making one bad decision based on vanity doesn't make you vain though IMO. It's not personal vanity either, it's "code vanity" so maybe a better word would be: hasty or risky...
Anyway, the effort that it takes to setup and use Prettier (which we use) or before that, "eslint --fix", is the least amount of effort of all the options.
You're expending more effort to memorize edge-case rules than my teams are if you're not using Prettier and if you are using Prettier but without semis, then you risk running into a bug like the one that broke Twitter Bootstrap due to lack of semis.
It's just a bad decision.
> I think people who really care about semicolons in JS are people who just don't write a lot of JS...
> I'm aware styleguides recommend semis but I'm more referring to people who have strong opinions about what is a minor semantic.
It's not just some guides, it's the majority of the most popular style guides and the biggest JS-using companies that write and use those guides, which recommend semis.
It's also not a minor semantic. The language requires them and if you make the error of omitting them, the runtime will try and correct your error. Depending on this runtime behavior is the kind of hasty and shallow decision that costs real money. That's why the most popular style guides recommend them and that's why the de fact standard is to use them. Googles style guide requires them company wide. The people who wrote these guides really cared about semicolons, that's why they put it in the rules.
You're not wrong, but using it as an argument has a counter: people like semis because they're the old-guard curmudgeons afraid of change :)
> then you risk running into a bug like the one that broke Twitter Bootstrap due to lack of semis.
The bug was due to a JS minifier removing a needed semi, which they did to save space. I still don't know of an example of somebody actually shipping code that broke due to a missing semi in source.
> It's also not a minor semantic. The language requires them and if you make the error of omitting them
That's not true at all. ASI is intentionally a part of the language spec, hence why there's not a single runtime that allows you to turn it off.
> The people who wrote these guides really cared about semicolons, that's why they put it in the rules.
The people who wrote those guides were writing them for hundreds of developers with varying levels of experience and a wide variance in tech stacks. I probably would have put it in the spec too, but that doesn't mean I don't set `semi: false` in every React project I start.
I'm not using it as an argument. I'm using it as a descriptor for people who make arguments against semis.
> ASI is intentionally a part of the language spec...
Yes, but it's clearly there as a corrective measure for people who mistakenly omit them. So, the spirit of the language spec and all signs point to: use them.
> I probably would have put it in the spec too, but that doesn't mean I don't set `semi: false` in every React project I start.
To write a spec rule and then immediately ignore it makes no sense to me.
But anyway...why do you not want semis? If you have a tool that automatically inserts them, like prettier or eslint, then the only reason you're making that decision is because you don't like the way they look. That's pretty shallow reasoning IMO.
Doesn't change the point: "back in my day, we used semicolons everywhere..."
> Yes, but it's clearly there as a corrective measure for people who mistakenly omit them. So, the spirit of the language spec and all signs point to: use them.
I think you're projecting quite a bit here. If you're interested, here's a ticket from TC39 proposing directly discussing possible issues with ASI: https://github.com/tc39/ecma262/pull/1062/files
Point being they're not advocating for using semicolons, but making it clear what the possible edge cases are.
> But anyway...why do you not want semis?
Because I don't want the noise. Yeah, theoretically they might save you some time debugging once in a few million LoC but including them everywhere adds a whole lot of pointless characters.
I started JS in the mid 90's. I still use semi-colons. To me it's like using a period to end a sentence. It's a pause. It defines the end of a statement.
I feel that too much emphasis is placed on the desire to remove curlys and semi colons from JS. It's part of the language. There's always coffeescript or those other flavours that will suit you.
No warning, no error and completely valid code. It really triggered my proverbial OCD. That one function out of ten where I made that typo.
So I stopped, and it was a major relief. Note that I didn't use a linter at that time.
I don't really mind semicolons in languages where they are enforced, but I also don't end statements in Python with semicolons.
No. It either does or it doesn't. The spec is not ambigous.
Learn how ASI works, or you will run into trouble no matter if you prefer semis or not.
I'm not sure I understand why it's wrapped in an enclosing function, though; you can reproduce the error with just:
(() => console.log("Hello"))()
(() => console.log("World"))()Thats like neglecting punctuation in English You can but the punctuation makes it much easier to read
A better analogy might be the Oxford comma.
Python and Ruby support semicolons for occasional statement termination; why is JavaScript any different? I can't help but think "semicolons by default" would be regarded as ritualistic if the practice was never popularized in the first place.
I also prefer void function () {} for this. Void the result of this function expression which I immediately invoke.
Always prepend any line that begins with ( and [ and ` with ;
It really is that simple.
I do agree that good use cases are few and far between.
I don't really write IIFEs since let and const. I'm sure the outputs from babel/typescript/etc use them, but I don't really need to write them myself, now that we have proper block scoping.
And if I want to declare an array and immediately iterate over it, I just put it in a variable first. That gives it a name, too, which tends to improve readability anyways.
I work with Javascript / Typescript projects on both sides of the argument, and I have to say not using semicolons never seems to cause any problems. Especially not with auto formatting / linters around.
;(function () {
window.alert('ok')
}())
Which, just, eww.Just use semicolons. Everywhere, always. Then you can treat JS's parsing rules as the same as every other language, and not normally like every other language except when a line begins with one of a select set of magical charaters that need to be prepended with `;` for unclear reasons.
Just end lines with `;`.
But that's not always the solution, you still need to know when ASI kicks in and when it doesn't.
"just end lines with ;" isn't true in multi-line arrays, in multi-line objects, and a ton of other situations where a semi at the end of the line is a syntax error. And while i'm sure you know that and didn't actually mean "every" line, it just goes to show that you already have the knowledge of when to add them and when not to. But that knowledge is learned, and it isn't a simple rule by any means.
For example, the following code is probably not going to do what many beginners think it will do:
return
[
1,
2,
3,
];
Because the JS engine will insert a semicolon right after the return, and you will basically get `return undefined;` as the result.Semicolons at the end of lines or not, you still need to understand when they are inserted and when they aren't. The real solution is to use a linter which will check these cases for you. I don't care if you use them or don't, just make sure something else enforces it.
He only ever worked with his favorite layout, and we worked with ours!
I'm not a big fan of holy wars in programming, i'm fine with either even if I do prefer one style over the other, but at the end of the day I just hope that everyone involved understands that it's just a preference thing for the most part. Linters will catch the edge cases for both styles, and if you really can't adapt to using or not using semicolons in javascript, there are probably other issues at play.
Note: If you're often writing code like this, you may be trying to be too clever.
Clever short-hands are discouraged, in favor of clear and readable expressions, whenever possible.
Instead of this:
;[1, 2, 3].forEach(bar)
This is strongly preferred: var nums = [1, 2, 3]
nums.forEach(bar)Or if you're serious, switch to BuckleScript and reduce all your side-effecting expressions down to unit. (Fully eliminates unhandled promise bugs, for one thing.)
void function () {
window.alert('ok')
}()
So much cleaner.Or better yet, stop using IIFEs. Unless you need IE11 support and can't transpile your code there is absolutely no need.
{
let x = 42
}
console.log(typeof x) // undefinedWith dangling balls: `(function(){})()`
No dangling balls: `(function(){}())`
There were obvious errors in my mind that I would fix without knowing the whole dissertation on why it happened.
So maybe if the question was, "Can you repair this code", I would excel.
It is likely one of these "trust your gut" situations.