🍬Syntactic sugar, diabetes alert🚨

11 June 2019 | By Maya Shavin | JavaScript, Syntactic sugar, Best practice, ES6

Syntactic sugar is everywhere in JavaScript. Most will say it's JUST syntactic sugar - a tiny bit of candy that makes your coding life sweeter. Well, is it? A little bit of sugar here, a bit there… and before we know it, we already need an insulin shot.

Let's find out how to keep your sugar balanced, shall we?


Syntactic sugar? No, it's syntactic SUGAR!

First, let’s have a quick look at the definition of syntactic sugar 🤓

Syntactic sugar is a syntax aimed to express the same code command in different and mostly better ways, in the same language.

For example:

  • a Array.prototype.filter is an alternative to  forEach loop for filtering out an array according to a specific condition, and
  • i++ instead of i = i + 1
  • Or for is an alternative to while for the same purpose.
for loop is just syntactic sugar for while loop

So is it JUST syntactic sugar? No. In fact, syntactic sugar is more like Alternative Good syntax that is meant to empower your code with Simplicity, Usability, and make your code more Readable.

Or as I like to remember it, the SUGAR rule.

Keep the SUGAR on because...

KISS works well with SUGAR

Yup, the following code

//Before syntactic sugar
const result = [];

for (let i = 0; i < data.length; i++) {
  const x = data[i];
  
  if (x % 2 === 0) {
    result.push(x);
  }
}

can easily be replaced by the syntactic sugar filter, with a proper refactor and 💥

//After
const isEven = number => number % 2 === 0
const result = data.filter(isEven)

Shorter, more concise and easier to read.

When SUGAR's in good use, it is extremely sweet and harmless

If you use syntactic sugar correctly, you can absolutely avoid silly but annoying JavaScript “weird” traps (as expected for being so magical 😆), such as the Deadpool BaNaNa trap — causing by having to type too many + to compute string from other strings and variables — like below:

Deadpool banana JS trap

With the magic of string template:

const banana = `ba${fillme}a`

Usability at its best. 😉

SUGAR is not only about less code, it's also about efficiency

Such as code writing efficiency, and performance relatively. As we all know, [] is a better performance choice compared to new Array(). Similarly with {} instead of  new Object() or even Object.create().

However, note that in general, performance efficiency really differs per use case.

And that’s when SUGAR flashes the 🚨warning sign.


Beware of JavaScript Diabetes

Everything has a limit before it becomes unbearable. No exception. Too much salt will cost you your blood pressure. Too much protein will cause indigestion. But you do need them, within a right amount.

Same goes to syntactic sugar. It’s sweet, easy to use, hence we developers are tempted to switch to it whenever we can (who wouldn’t love easy solution?) — sometimes without even considering possible negative effects. Because as long as it is within KISS, it’s good.

Is it? No, absolutely not.

Less code !== More readability

Let’s look at the following code:

Only 2–3 lines of code, concise and short.

However, is it easy to get straight away what this block of code does? For some of you who are familiar with the problem, which the above code is trying to solve, it’s not too hard to figure out.

(it’s for flattening an array, in case you are curious).

But for first timer, it’s challenging.

Readable? Not really.

... operator is another example.

Lovely, but also hard to interpret sometime, due to the fact that it can be spread operator or rest parameter is quite confusing for many developers, especially when both are presented in the same context as above.

Remember, your code needs to be clear and straightforward before everything else, for the sake of the next developer. Hence, without readability, your beloved syntax is no longer syntactic SUGAR.

Concise code !== Better performance

While less code does mean lighter JS file, it doesn’t necessarily make the performance better, such as:

This function, theoretically — without considering inner loop combinations.map() —   takes O(n). Linear time - should be good, right? But that’s just in theory.

Why? Because:

  1. map loops through the original array, creates new array based on it and returns the new array — new resource is allocated. Same goes to filter, reverse, etc...
  2. reduce also requires to loop through the new array again, and returns a reduced value based on that array with a calculation formula passed.
  3. Each of these calls are known to be much slower than the original for loop, regardless how optimised the JS profiler is built.
  4. JavaScript is single-thread. This means while it is in a loop, the browser is technically pausing and waiting for the iteration to complete before moving on the next piece of code. Hence the bigger the array is, the more logic to execute, the waiting time will be longer — user will start seeing browser “frozen” more obvious. Linear time doesn’t really apply in this case.
  5. In addition, chaining calls like map and reduce here will only make the matter worse, not better (browser needs to “freeze” for the first map to complete, and then again for reduce to complete, and so on).
  6. for loop is not in a need of syntactic sugar that badly. We can rewrite the above code using for and stills maintain KISS rule with efficiency (both in resource allocation and performance)

Apparently the syntactic version is way slower than the classic for as in a performance test, despite of the same time efficiency (O(n²)).

In short, it’s O(n) but NOT always O(n), so be careful. Sometimes it’s better to use the classic for loop. Period.

Browser.support(syntactic sugar)?

Exactly, not all syntactic sugar is supported in every browser. That’s why we need Babel — for instance — to make it works.

Yup. Remember our little friend IE (or even Safari 9+?). Some of ES6 syntactic sugar like ... and for..of will not be supported, and suddenly your following sweet and clean code which originally looked like this

const sumUp = (...numbers) => {
    let sum = 0;
    for(const number of numbers) {
        sum += number;
    }
    return sum;
}

After going through Babel’s compiler, will become (sort of):

var sumUp = function sumUp() {
  for (var _len = arguments.length, 
        numbers = Array(_len), _key = 0; 
        _key < _len; _key++) {
    numbers[_key] = arguments[_key];
  }
var sum = 0;
  for (var _iterator = numbers, 
      _isArray = Array.isArray(_iterator),
      _i = 0, 
      _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
    var _ref;
if (_isArray) {
      if (_i >= _iterator.length) break;
      _ref = _iterator[_i++];
    } else {
      _i = _iterator.next();
      if (_i.done) break;
      _ref = _i.value;
    }
var number = _ref;
sum += number;
  }
  return sum;
};

And it suddenly becomes not that efficient anymore 😅

As long as your users still use certain browsers, your code needs to work well on them. Thus before putting a new syntactic sugar in your code, don’t forget to double check or read the instructions (aka the documentation).

Being extra careful with new syntax is always a good habit 😉.


Conclusion

In general, syntactic SUGAR is good (and totally recommended) to use, as long as it is accompanied with CARE, which is:

  • C — Check your use case, the syntax pitfalls and make sure your new code go well with your existing logic.
  • A — Ask for review (code review, architecture review, etc). The best one to ask for a code review, to my opinion, is junior developers, or someone new to the team. Obviously while an expert eye is great to have, a junior or new team member will have a fresh look and can give you straight away whether your code is easy to understand. As much as I agree on respecting developers’ personal taste on coding, an extra pair of eyes or 2nd opinion is absolutely needed, for a better reason.
  • R — Read the documentation, read others’ code and remarks. In addition, make your code readable by providing a README file or explanation comments. But only when needed, because…
  • E — Explicit. Your code should stand for its own. Split the logic into smaller parts if it helps other to understand. Good code means less or no comment 😉. Why do you need comments if your code is readable and explicit enough, right?

To sum it up, code responsibly — think of efficiency, maintainability, readability for other developers 🤞. As long as you know your sugar limit, your syntactic sugar will be sweet 🍬 and there will not be any risk of diabetes 🚀.

Disclaimer: This article is based on my talk on the same subject in CityJS Conf 2019 last May. A recorded version is available on Youtube. Enjoy and happy coding everyone! 😸

If you’d like to catch up with me sometimes, follow me on Twitter | Facebook or simply visit my portfolio website.