`Math.max`

in JavaScript

JavaScript is a fine language in many ways — a fact that many people have
noticed by now. But one of its biggest problems is the design of
its standard library. There’s a lot of low-hanging fruit to complain about;
this note covers just `Math.max`

.

`Math.max`

in JavaScript does essentially what you’d expect: it calculates
the maximum of several numeric values. It also does something very sensible
if you give it no values at all: it returns `-Infinity`

.

If you need to use `Math.max`

, you will be in one of two situations: you
might have several numeric variables, or you might have an arbitrarily-long
array of numeric values.

In some languages, like Perl 5, the distinction isn’t meaningful:

```
use List::Util 'max';
my $max_of_array = max(@array);
my $max_of_variables = max($x, $y, $z);
# For that matter, you can use any combination:
my $max_of_all_sorts = max($x, @array, $y, @array2, $z);
```

But in JavaScript, that approach isn’t possible; the API has to pick one form or the other as the “native” approach, and force the other to be implemented in terms of it. So when designing a standard library for a JavaScript-like language, which approach should you pick?

The obvious way of tackling that question is to look at the consequences of each decision. Suppose the array form were considered the “native” approach. Then you’d have code like this:

```
var max_of_array = Math.max(array);
var max_of_variables = Math.max([x, y, z]);
```

You could also consider making `max`

a method on an array object, instead of
a pseudo-`static`

method called on its namespace object:

```
var max_of_array = array.max();
var max_of_variables = [x, y, z].max();
```

That seems particularly concise and obvious, but even using the spurious
`Math`

namespace, it’s easy to call `max`

on either an array or a list of
named variables. And of course, that’s because building an array from a
list of named variables is trivial in terms of both cognitive and syntactic
weight.

The other API approach — making the multiple-variables form the “native” one — yields straightforward code when that’s what you’re trying to do:

```
var max_of_variables = Math.max(x, y, z);
```

But if you have an array of values, the best you can do is this monstrosity:

```
var max_of_array = Math.max.apply(Math, array);
```

Not only do you have to explicitly invoke `apply`

on `Math.max`

, you also
have to redundantly say *again* that `max`

belongs to `Math`

. By any
reasonable standard, this approach yields a worse API than the other one.

So, why does JavaScript use this worse API?

It’s obviously way too late to change JavaScript’s standard library now. And I’m aware that the difference here is of limited impact — It’s not absolutely terrible that JavaScript programmers have to jump through this hoop to find the maximum of an array of numbers. But that doesn’t justify use of a suboptimal API design in something as widely used as a language’s standard library. The argument’s somewhat trite, but if an improved API could save one second for each of a million people, that’d be a big win.

I’ll also point out that, since JavaScript is designed for use on the web, excessively-verbose APIs hurt the end user as well as the programmer — the user effectively has to download the source code.

Depressingly enough, though, the situation as presented above isn’t
actually as bad as it gets. The first browser to have JavaScript was
Netscape Navigator 2.0. (Unsurprisingly, given that the language was
developed in-house at Netscape.) Array literals first made an appearance
in JavaScript 1.2, which came with Navigator 4.0. In the absence of
array literals, using an array-oriented `max`

API for a list of variables
becomes rather more awkward:

```
// Convenient form, as above:
var max = Math.max([x, y, z]);
// Or without array literals, ugh:
var max = Math.max(new Array(x, y, z));
```

Worse even than that, though, is the fact that before ECMAScript
edition 3, the `Math.max`

function *didn’t* calculate the maximum of an
arbitrary number of arguments. Instead, it took exactly two arguments,
and returned the greater. That is, JavaScript’s mid-1990s API designers
not only failed to find the better of the two obvious choices, they even
failed to find the worse one. D’oh.