When semicolons matter

Introduction

Younger I was a dogmatic developer blindly enforcing the IT gurus’ dogma, later I’ve become more pragmatic preferring code readability and maintainability.
In JavaScript, it means omitting the semicolons to lighten the code and remove useless ceremony.

But in some rare corner cases omitting a semicolon can completely change the way the compiler interprets the code.
Hopefully, it will cause a compilation error, and in the worst case a hidden bug hard to track.

In this article, I describe one of these corner cases.

A simple code

Here is a basic JavaScript code snippet whose meaning is quite obvious for a human developer:

var evens = [], odds = []

var n = 123

console.log("n is %s", n % 2 === 0 ? 'even' : 'odd')

(n % 2 === 0 ? evens : odds).push(n)

If n is even it is added to the evens array, otherwise to the odds array.

A strange error

But compiling it raise a TypeError:

(n % 2 === 0 ? evens : odds).push(n)
^
TypeError: console.log(…) is not a function
at Object. (C:\Temp\test.js:7:1)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

The error is telling that we cannot call the return value of console.log as it is not a function!

Apparently, the compiler has misunderstood our intent.

What the compiler sees

Indeed here is how the compiler interprets the last lines:

console.log("n is %s", n % 2 === 0 ? 'even' : 'odd')(n % 2 === 0 ? evens : odds).push(n)

Not the same meaning at all, here the call to the return value of console.log is obvious.

Clarifying our intent

To help the compiler understand that we have two separate instructions we must separate them with a semicolon:

console.log("n is %s", n % 2 === 0 ? 'even' : 'odd');

(n % 2 === 0 ? evens : odds).push(n)

Now the code runs as expected pushing n to the relevant array.

Conclusion

Even after years of practice JavaScript can still surprise you with subtle errors you would not get in other languages.

Let’s say this is what makes it somehow flavorful. 😉

Leave a Reply

Your email address will not be published. Required fields are marked *

Prove me you\'re human :) *