JavaScript/Higher-order programming/Example 2
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.