archives

« Bugzilla Issues Index

#2465 — Missing step in ToNumber / Redundancy in definition of Number.prototype.clz.


The steps in the definition of Number.prototype.clz begin:

1. Let x be thisNumberValue(this value).
2. Let n be ToUint32(x).

The definition of ToUint32 begins:

1. Let number be the result of calling ToNumber on the input argument.

It seems like it would be preferable, for consistency, to omit step 1 of Number.prototype.clz (and similar methods) and have the first step be "Let n by ToUint32(this value)".

This implies that `ToNumber` should return the same result as `thisNumberValue`, that is, the following steps should be performed by `ToNumber`:

"If Type(value) is Object and value has a [[NumberData]] internal slot, then
Let n be the value of value’s [[NumberData]] internal slot.
If n is not undefined, then return n."

That could either be folded directly into the definition of `ToNumber`, or else added to `ToPrimitive` when the "number" hint is given (or even pushed down into the definition of @@toPrimitive for classes which define the [[NumberData]] internal slot).

These changes would make the first two steps exactly equivalent to "var n = this >>> 0" instead of requiring an additional step: "var n = Number.prototype.valueOf.call(this) >>> 0". It would also make the ToNumber internal operation more consistent with the methods defined on Number.prototype.

See https://github.com/paulmillr/es6-shim/pull/196 for some related discussion.


A closer reading reveals that thisNumberValue also has the side-effect of throwing a TypeError if this value is not sufficiently numeric. So I would recommend changing step 1 to a simple type check (perhaps using a new "checkNumberValue" helper). IMO it would still be useful to ensure that the numeric results of `ToUint32(n)` and `n >>> 0` are identical; that is, the `ToNumber` operation should include the check of the `[[NumberData]]` internal slot.


Apparently Number.prototype.clz() is going to become Math.clz32(n).

Since all of the Math.* functions perform ToNumber on the arguments, again it seems that the ToNumber algorithm ought to look at the [[NumberData]] internal slot.

And presumably the type-check and TypeError of thisNumberValue would be replaced by returning NaN to be consistent with the rest of the Math.* functions.


both ToNumber and ToUnit32 date to the earliest days of ES and are widely used in the ES spec. Changing, there semantics, for example by not calling valueOf on Number wrapper objects, could break existing code.

However, implementations are free to optimize algorithms in any manner that has no observable effect.

For example, Math.clz32(x) implicitly does:
ToUint32(ToNumber(x))

I would expect implementations to note that the ToNumber operation in step 1 of ToUint32 has no observable effect and can be skipped.

ES operation upon [U]int32 values consistently treat NaN as 0 rather than throwing. The current spec. for Math.clr32 is consistent with that behavior just like Math.imul.