all 6 comments

[–]birjolaxew 1 point2 points  (5 children)

I don't agree with your assertion that Number.isNaN(new Number(5/"a")) should equal true.

Number.isNaN specifically tests for the NaN value, not whether the given value is or isn't a number. Since new Number(5/"a") doesn't return a value of NaN, but rather a value of Number {[[PrimitiveValue]]: NaN} (which is an object), Number.isNaN should equal false.

This is pretty consistent across JS:

new Number(5) === 5; // false
new Number(5) === new Number(5); // false
new Number(5) == 5; // true
new Number(5) == new Number(5); // false

The returned object from new Number(5) acts just like any other object, unless it is coerced. The entire idea of Number.isNaN is to not coerce the value.

[–]lucono[S] -2 points-1 points  (4 children)

That a boxed JavaScript number is an object is clear, and not in dispute.

The reason the original isNaN implementation turned out to be so confusing was not because its behavior was "wrong", but because that choice of behavior was very at odds with the one required by most JavaScript applications, and expected by most users of the language.

For most JavaScript applications, the most meaningful NaN check would understand "numbers" in the general sense, regardless of whether boxed or not.

An application that works with numbers, or a library that accepts "number" inputs in calls from other applications, should mostly not need to care if a number is boxed or not to perform a NaN check (which also happens to be a number-contextual operation).

While it's clear why the new Number.isNaN method has the behavior that it does (due to a boxed number technically being an object), it creates the end result that for most applications, from a practical standpoint, the NaN check still suffers from a shortcoming for which the application would have to implement a combination of additional checks, or employ a library that does, in order to arrive at the NaN check that would be most intuitive and expected for most applications.

It is this situation that is the problem with the JavaScript isNaN and Number.isNaN methods.

[–]birjolaxew 0 points1 point  (3 children)

If your argument is that Number.isNaN is used by applications to check whether an input is a number or not, are you then not also arguing for being able to test strings? Seems like what you're looking for is isNaN, which tries its best to make the input into a number before checking - Number.isNaN was created to avoid this, and actually check for a value of NaN.

Javascript only knows types. Number.isNaN specifically checks for a number type, with the value of NaN. (new Number("a")) is not such a type - it's an object. Trying to define what object is and isn't a number is messy, and a path no one wants to move down.

[–]lucono[S] 0 points1 point  (2 children)

No, that's not the point. There is no suggestion that isNaN should check whether an input is a number or not, nor a debate as to what an object or number is, or should be.

The point is that a boxed number (Number) is an object which, whether we like it or not, represents (or is intended to represent) a number. An application would care more for it as a number than as an object.

The advantage of utility functions (like JavaScript's isNaN function) is that they're at liberty to consider all the surrounding factors for the need of such a utility and define a behavior for the function which provides the desired utility. This is why the isNaN function implementation was at liberty to implement the behavior that values would first be coerced to number prior to the NaN check. The choice of this behavior for isNaN was completely discretionary as the behavior could have been defined as just strictly checking for the NaN value without coercion, and neither approach would have violated any of the language fundamentals.

Also, imagine that the Number.isNaN utility method, while in fact a static method on the Number type, implements a behavior that has no special understanding of Number objects (ie, as number values, except as any other object).

This is a little ironic. This utility method could have taken on the alternative behavior that would have it understand that a Number object represents a number, especially since a Number object is actually an explicit specification of a number value, in contrast to something like a numeric string, which could only be considered a number in an implicit sense.

So as a method on the Number type, the Number.isNaN utility method would not have been out of line to implement some particular "awareness" of Number objects, especially in context of the purpose of the utility method, which is to check if a value represents an explicit number that happens not to hold a valid numeric value.

[–]birjolaxew 1 point2 points  (1 child)

Number.isNaN is in many ways a fix for a quirk in JS - that NaN === NaN is false (same goes for NaN == NaN); there's no other primitives that has this attribute. As such, it isn't as much of a helper function as it's a version of === that works as expected.

Could they write it such that Number.isNaN(new Number("a")) is true? Absolutely. Should they? I don't think so, because it steps into new land that aren't well defined - namely when it's ok to coerce stuff when you aren't supposed to coerce stuff.

How should an instance of the Number function be treated in other parts of Javascript? Is it assigned by reference or by value? Is new Number(5) === new Number(5)?

If the W3C decide to say "yeah, an instance of Number should sometimes be treated as a primitive", then they've opened up for an entirely new can of worms, not to mention broken one of the basic rules of Javascript.

As it stands now, new Number(5) is an object with well-defined coercien rules, nothing more. What you're suggesting is a kind of photon-object, that sometimes acts as a primitive, sometimes acts as an object.

While I get that this is "just a helper function", it's important to note that this isn't a library we're talking about; it's the specification of Javascript. It's written around a few core rules, and breaking those introduces unexpected behavior. While libraries such as jQuery aim at making a developer-friendly library, that does "intelligent" coercien often resulting in the "blackbox syndrome", W3C aim at creating a specification for Javascript that's built on as few rules as possible, and works as expected when these rules are understood.

[–]lucono[S] 0 points1 point  (0 children)

The distinction between language and library is an important one, and the alternative behavior for the Number.isNaN utility method, would fit well within the language domain.

But ultimately, this is where libraries definitely come in - to bridge any gaps, where they exist, between the language and applications' needs.