
Can You Find the Bug in This Code? - vzhou842
https://victorzhou.com/blog/a-javascript-bug-i-had-once
======
slyrus
It's too bad there isn't a less ambiguous way to write programming language
expressions with, say, prefix notation, using a single set of characters (open
and close parens maybe?) to describe the tree, etc..., and getting rid of
semicolons and curly braces altogether.

~~~
Jim_Heckler
And perhaps we could repurpose those semicolons for comment syntax ;-)

------
scandox
The real bug is the failure to use semi-colons. I literally cannot comprehend
the non-use of semi-colons in JS.

~~~
adrianhel
If so, the failure lies with the spec. (personally, I like ASI)

~~~
nobleach
I feel the same way about ASI as I do about forgiving HTML parsers. They're
built to handle mistakes made by your average weekend warrior Grandpa building
a website about his grandkids and pets. ASI is built to handle an "oops", not
an entire codebase. That's why there are these odd edge cases. The same is
true with the English language. If one were to send me a text with "do ya
think" I'd probably figure out that it was a question... but why avoid the
actual punctuation that assures that I communicate the intention 100%?

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™

~~~
ng12
> 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.

Honestly -- then they'll never be convinced. I haven't hit an ASI bug in the
last decade.

------
mrspeaker
Over the years I've submitted pull requests to 3 different projects that
consist of a single semicolon in a semicolon-free codebase. They can be sneaky
bugs to catch!

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.

~~~
adrianhel

        ;['but', 'why']
          .reduce((msg, word) =>
            msg + word,
            ''
          ).join(' ') +'?'

------
Etheryte
An even more common use-case that fails without semicolons by T.J. Crowder
(2015): [http://blog.niftysnippets.org/2015/09/automatic-semicolon-
in...](http://blog.niftysnippets.org/2015/09/automatic-semicolon-
insertion.html)

There are a number of cases where not having semicolons has its downsides, I'm
yet to see a single case of an upside.

~~~
beering
> 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.

~~~
ng12
I disagree, I think people who really care about semicolons in JS are people
who just don't write a lot of JS. I can honestly say in the last 5 years of
only writing front-end I have never been bit by ASI.

~~~
wayneftw
_The most popular_ JS style guide from AirBnB uses semi-colons. Google and
Facebook uses semi-colons. I'm pretty sure they collectively write way more JS
than you do.The most popular code formatter also defaults to having semi-
colons because they know it's the de factor standard in JS. I myself have been
writing JS since the late 90s (around the time when XHR was introduced) and
it's been my most used language for easily the past 15 years.

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.

~~~
ng12
> 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.

~~~
wayneftw
> I'm sure they love being told they're wrong because they're young and vain.

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.

~~~
ng12
> 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

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.

~~~
wayneftw
> You're not wrong, but using it as an argument has a counter...

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.

~~~
ng12
> I'm using it as a descriptor for people who make arguments against semis.

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](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.

------
Legogris
Semicolons are usually optional in JS. The 'usually' part if why it's a good
idea to enforce usage of them to avoid situations like this. You don't even
need to do IEEs for this - running a function on an inline-declared array has
a high probability of creeping the array up as an index on the previous
expression.

~~~
adrianhel
> Has a high probability of...

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.

~~~
Legogris
You misinterpreted my statement - it will or will not make a difference
depending on the line before. The spec is not ambiguous but for someone who
does not know this there is probability at play.

------
czr
Happy to say I caught this, although I would credit that as much to having
taken a compilers course as any JS knowledge.

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"))()

------
tastyfreeze
What kind of heathen omits semicolons in JavaScript

Thats like neglecting punctuation in English You can but the punctuation makes
it much easier to read

~~~
programmarchy
Lot's of people! [https://standardjs.com](https://standardjs.com)

A better analogy might be the Oxford comma.

------
jbredeche
Reminds me of
[https://github.com/twbs/bootstrap/issues/3057](https://github.com/twbs/bootstrap/issues/3057)

------
TeffenEllis
I think what's more confusing than ASI are the mental gymnastics developers go
through to justify typing semicolons daily, rather than installing a linter
once, or reading the ASI spec.

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.

~~~
kurtisc
Does pressing a key on the home row really require a lot of justification? A
project doesn't care how effective my tooling is if the next person doesn't
have it.

------
adrianhel
Always prepend ( and [ with ;

I also prefer void function () {} for this. Void the result of this function
expression which I immediately invoke.

~~~
ezekg
I'm not sure _always_ prepending those with ";", but definitely when needed,
sure. But most of the time you can simply refactor the code a little bit and
improve readability with the addition of a single variable.

~~~
adrianhel
Always for ( and [ when they start a statement.

It really is that simple.

~~~
dvlsg
I honestly can't remember a recent time I had to start a line with a ( or a [.

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.

------
telekid
I ran into this in the pre-webpack era where it was somewhat common to just
concatenate JS together in a gulp build step. We imported code from two NPM
modules, and each one was wrapped in an IFEE, but the first one didn't
terminate with a semicolon. Not fun to debug.

------
ezekg
I refuse to use semi-colons in TS/JS, unless that conflicts with existing code
standards. I feel like it's as if I'm using semi-colons in Go. This can easily
be avoided by writing clearer code.

~~~
ezekg
Relevant:
[https://standardjs.com/rules.html#semicolons](https://standardjs.com/rules.html#semicolons)
(hint: no semi-colons!)

~~~
joshuamorton
Which also recommends

    
    
        ;(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 `;`.

~~~
Klathmon
>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.

~~~
joshuamorton
You're absolutely correct. Jey provided the better phrasing of my comment: Use
`;` to end a statement. The point I'm making is more bias toward using `;`,
even when not strictly "necessary". This brings JS's statement parsing in line
with most other languages. And yes, absolutely use a linter.

~~~
Klathmon
Or you can do what a past coworker did. We settled on standard.js for our
linting in a project, and they don't use semicolons. The coworker hated this,
so he setup his editor to auto-format into his preferred style on load, then
on save use the auto-format option in standard.js to save it as the format
that we agreed on in the repo.

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.

~~~
ezekg
This made me laugh out loud. I identify with the sentiment (I can get pretty
pedantic about how code looks), but I wouldn't take it to _that_ extreme.

------
jakear
My problem with semi-colons is that when you force semicolons in a tslint
config, applying an autoformat on a malformed input (forgetting a closing
curly brace, for instance) will introduce a bunch of erroneous semicolons
throughout the file, giving you a ton of syntax errors to clean up. If you’re
lucky you’ll be able to undo before you continue, but I sometimes don’t notice
until I’ve done a bunch of other work

------
kowdermeister
When you assume the compiler reads it the same way your brain does :)

------
jyriand
“Must be a semicolon issue,” was my first thought, without actually knowing
why.

------
tniemi
Don't use "gonad" javascript, or just use semicolons.

With dangling balls: `(function(){})()`

No dangling balls: `(function(){}())`

[https://gist.github.com/newswim/4668aef8a1f1bc0dabe8](https://gist.github.com/newswim/4668aef8a1f1bc0dabe8)

------
mikewhy
Another instance where TypeScript has your back.

------
kgwxd
The bug is in the coder.

------
gammateam
I feel good that my first thought of fixing it would have created the
solution.

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.

~~~
Someone1234
Ditto. I didn't know it was a missing semicolon, but the code smells bad
regardless and my solution also would have solved it another way (just by
improving code readability/clarity).

It is likely one of these "trust your gut" situations.

