Hacker News new | comments | ask | show | jobs | submit login
Can You Find the Bug in This Code? (victorzhou.com)
43 points by vzhou842 4 days ago | hide | past | web | favorite | 60 comments





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.

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

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

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

Cue Principle Skinner meme:

"Is the language specification too loose?"

"No, it's the developers who are wrong."


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™


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


Close to 100% of semi-colons are noise in any given project. That's why.

Samewithwhitespace.

Not true. I'd really like an example where semicolons make JS more readable, if that's your argument. If you're using something like Prettier (and you should be) your code is formatted identically whether or not you use semis.

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.


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

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

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


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


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.

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.


> 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'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.


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


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


> 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

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.


> people who really care about semicolons in JS are people who just don't write a lot of JS

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.


The reason why I made the switch was that it really irked me when one line missed a semicolon.

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.


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.

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


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.

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

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


Lot's of people! https://standardjs.com

A better analogy might be the Oxford comma.



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.


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.

Always prepend ( and [ with ;

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


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.

More correctly it's:

Always prepend any line that begins with ( and [ and ` with ;


Always for ( and [ when they start a statement.

It really is that simple.


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.


And for template strings: `

I do agree that good use cases are few and far between.


I agree. Those are the only two cases where a semicolon is needed. Other than that, I like my code to look clean :)

Correction: void function () {}()

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.

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.


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.


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.

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

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


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


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.

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.


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.

Which also states this, directly under that "bad" example:

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)

The irony is that building a language which avoids semicolons by automatically inserting them is arguably taking a clever short-hand in favor of unclear and ambiguous expressions.

Or just don't use classic IIFEs

    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) // undefined

Yeah, use ";" to denote the end of a statement.

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.)


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

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

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

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

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

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

https://gist.github.com/newswim/4668aef8a1f1bc0dabe8


Another instance where TypeScript has your back.

The bug is in the coder.



Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: