Can You Find The Bug in This Code?

This is an actual bug I had once.

Here’s a bit of Javascript that prints “Hello World!” on two lines:

(function() {
  (function() {
    console.log('Hello')
  })()

  (function() {
    console.log('World!')
  })()
})()

…except it fails with a runtime error. Can you spot the bug without running the code?

Scroll down for a hint.









Hint

Here’s the text of the error:

TypeError: (intermediate value)(...) is not a function

What’s going on?

Scroll down for the solution.









Solution

One character fixes this code:

(function() {
  (function() {
    console.log('Hello')
  })();
  (function() {
    console.log('World!')
  })()
})()

Without that semicolon, the last function is interpreted as an argument to a function call. Here’s a rewrite that demonstrates what’s going on when the code is run without the semicolon:

const f1 = function() { console.log('Hello'); };
const f2 = function() { console.log('World!'); };

f1()(f2)();

There are 3 function invocations in that last line:

  • f1 is called with no arguments
  • The return value of f1() is called with f2 as its only argument
  • The return value of f1()(f2) is called with no arguments

Since the return value of f1() is not a function, the runtime throws a TypeError during the second invocation.

With the semicolon added, this becomes:

const f1 = function() { console.log('Hello'); };
const f2 = function() { console.log('World!'); };

f1();(f2)();

Which runs as expected.

Wait, you had this bug once?

Yup.

Why would you ever write code with so many Immediately Invoked Function Expressions (IIFE)?

It’s a long story, but I’ll make a post soon explaining how I wrote bad enough code to have this bug. Subscribe (no spam, for real) if you want to get notified when it’s published!

UPDATE: I followed through and made that post.

The Lesson

Always use semicolons. This specific case was a bit contrived, but something similar could happen to you. Here’s another Hello World program that fails for a related reason:

const a = 'Hello'
const b = 'World' + '!'
[a, b].forEach(s => console.log(s))

I’ll leave figuring this one out as an exercise for you.

Most Javascript style guides require semicolons, including Google’s, Airbnb’s, and jQuery’s. To summarize: always use semicolons.

I write about ML, Web Dev, and more. Subscribe to get new posts by email!


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

This blog is open-source on Github.

At least this isn't a full screen popup

That would be more annoying. Anyways, consider subscribing to my newsletter to get new posts by email! I write about ML, Web Dev, and more.


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.