Consider rewriting BigInt(value) only convert to a primitive once

Let's take a look at 21.2.1.1 BigInt(value) from /numbers-and-dates.html#sec-bigint-constructor-number-value.

The first step is to convert the value to a primitive value, hinting towards a number. If the primitive is not a number, then we reach step 4, asking us to jump to ToBigInt(value), the first step of which is to then convert this value to a primitive again. See /abstract-operations.html#sec-tobigint.

This behaviour is observable to user JavaScript code, see: example on engine262.js.org.

The problem is that JSC, SpiderMonkey, and V8 all are incompliant here in that they replace step 4 of BigInt(value) with ToBigInt(prim), and skip the first step of ToBigInt(argument).

Rather than create bug reports in current implementations, how about we re-specify this here in ECMAScript?

Once it's a primitive, how is it observable to convert it to a primitive again?

I think the point made is that the spec requires converting the initial value to a primitive twice if the first does not result in a number, which is observable, but that none of the common implementations seem to actually do. This sounds like a web reality the author suggest should be fixed by updating the spec.

const v = {
  [Symbol.toPrimitive]: () => {
    print("called");
    return "10";
  },
};

print(BigInt(v));
#### engine262
called
called
10

#### JavaScriptCore, Moddable XS, SpiderMonkey, V8
called
10

Note the difference between ToBigInt(value) and ToBigInt(prim); the spec does the former, implementations do the latter.

Yes, I concur: this is precisely what I seek to do here by raising this discussion.
Thank you for that simpler example too!

Thanks for the report! I've opened Normative: only coerce once in BigInt constructor by bakkot · Pull Request #2812 · tc39/ecma262 · GitHub.

1 Like

FYI, the Committee approved the pull request at the plenary yesterday, fixing BigInt to coerce only once.

1 Like