JavaScript/Higher-order programming/Example 2

From Spherical
Revision as of 00:42, 15 June 2013 by Apollolux (talk | contribs) (created)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Say I've got this, an array of strings holding stats to be displayed in a box:

var stats = [
  "Hero L" + level,
  "Exp: " + exp + " / " + next,
  "",
  "HP: " + hp + " / " + hpMax,
  "MP: " + mp + " / " + mpMax
];

In order to draw a window style around it, we'll need to find out which line is longest.

The chump's way

var maxWidth = 0;
for (var i = 0; i < stats.length; ++i) {
  if (maxWidth < GetSystemFont().getStringWidth(stats[i]))
    maxWidth = GetSystemFont().getStringWidth(stats[i]);
}

What's wrong with it?

  • for loop is crappy - We're good coders, so we recognise that this looks for a maximum without even reading it. But if we really sat down and read it, we're looking at 20+ tokens spread across four lines. And this is just a simple loop. In a more complex loop body, a bug would be almost impossible to find.
  • Focus is on iteration instead of task - The variable i occurs in no less than 5 places. As it turns out later on, we don't even need it.
  • Copy-paste coding style - The body of the for loop has two lines which are almost identical. Copy-paste == more lines to change if a single line needs changing.

A smarter way

var maxWidth = reduce(function (a, b) {
  return a > b ? a : b;
}, 0, map(GetSystemFont().getStringWidth, stats));

Basically, the stats have been mapped from strings to their widths according to the system font, and those widths have been reduced to find the maximum of them.

Note that we can use Sphere's API functions with our higher-order functions, just by omitting the "call" parentheses.

Why it's good:

  • Less typing - Compare these to the chump's way. Do you really want to type all that? Less typing == less typos == less chance of errors.
  • No unnecessary index - I told you we didn't need the index.
  • No copy-paste - Copy-paste == bad. I shouldn't have to explain this.

An even smarter way

var maxWidth = Math.max.apply(null, map(GetSystemFont().getStringWidth, stats));

The kind folk behind Sphere's JavaScript engine gave us the standard JavaScript library. It doesn't include much, but it's got Math.max, which we can link with our own higher-order functions to do lots of heavy lifting.

Same benefits as the smarter way, plus it's shorter, and now the intent is very, very clear. This is what we're aiming for.