Can You Find The Bug in This Code?

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.

Here’s the text of the error:

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

What’s going on?

Scroll down for the 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?


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!

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.