a proposal for the Exponentiation Operator(**) to call Math.pow

I have a proposal to change the spec of the Exponentiation Operator, **.

Background

The exponentiation operator is useful, but it has a problem that the return value is an implementation-approximated value.

Other Math functions, such as Math.sin, return an implementation-approximated value as well, but we can change the behavior easily just overwriting the Math properties. When I needed to implement a playback feature of a physical engine, I did it with replacing Math functions with WebAssembly implementations, and this works well to align the result of Math functions among many modern browsers.

But considering the ** operator, there's no option to change the result despite the implementation dependent. My proposal aims to solve this issue.

Proposal: Change the Exponentiation Operator spec to call Math.pow for Number values

How about calling Math.pow function when evaluating the ** operator, like Array.prototype.toString method calling Array.prototype.join method?

The benefit is that developers can handle the implementation dependent behavior. This is important for web game developers who try to align the result among many platforms and browsers.

I believe almost all existing pages will not be affected of this change, and the performance degradation is also within acceptable range for almost all users.

The biggest difference between Math.pow and the ** operator is the BigInts support, but we may keep the support by just changing "6.1.6.1.3 Number::exponentiate" spec and leaving "6.1.6.2.3 BigInt::exponentiate" spec as is.

I've already implemented a game with a playback feature of a 2D physics engine, and the idea replacing all Math functions helped me a lot implement the feature. Luckily, the engine did not use ** operator internally, but if it does it's impossible to align the results without parsing the output JS file and replacing the ** operator to Math.pow. Considering the future of web usage, I believe this small change will help many game developers in near future.

1 Like

It's an interesting idea, but we'd generally like to avoid adding new places to hook syntax, since that makes every operation using the syntax more complex and potentially slower. Since this is such a niche use case, I think you'd be better served by just using your own pow function which has the implementation you'd like.

1 Like

Thank you @bakkot for the response.

Unfortunately, there's no workaround to avoid this problem. Your suggestion of making my own pow function will not be a solution, because my own pow function does not affect third party libraries, such as a physics engine. For other Math functions, like Math.sin, I can overwrite it before I use it like below, but I can't do the same thing to the ** operator.

<html>
  <head>
    <script>
      Math.sin = () => {
        // my own sin implementation which will be used by other libraries to avoid implementation dependent
      };
    </script>
    <script src="box2d.min.js"></script>
...

we'd generally like to avoid adding new places to hook syntax, since that makes every operation using the syntax more complex and potentially slower.

I agree with this idea. I think the merit will overcome the downside so I'd like to proceed it, but this point needs to be discussed very well.

I suppose that the complexity is not affected because this proposal does not change the existing syntax at all. Some implementation's optimization could be affected, but maybe the optimization around this operator is limited scope because the usage of the ** operator is not so wide.

The performance is another problem, but the ** operation is heavy and is already slow. So I assume that users who use ** operator may not be sensitive about the performance.

There's no workaround and the downside is limited, so I want to proceed it. However, my perspective about the language design is very limited, so please let me know if I'm wrong or making misunderstanding.

Your suggestion of making my own pow function will not be a solution, because my own pow function does not affect third party libraries

Ah, I had not understood that your goal was to change the behavior of code you don't control. We explicitly do not want to provide the ability for you to dynamically change the behavior of syntax in third-party libraries. The appropriate way to do this is to rewrite those libraries (possibly automatically, e.g. by using a babel transform).

I suppose that the complexity is not affected because this proposal does not change the existing syntax at all.

I disagree: it changes the meaning of existing syntax, in a way which adds complexity. In particular, where right now ** means "perform exponentiation", with your proposal it would mean "look up Math.pow, whatever that happens to be right now, and call it". This is a lot of overhead, both conceptually and in terms of actual runtime cost. And this overhead would be imposed on all code using **, while it provides benefit only to your very narrow use case. I think the small benefit is not worth that substantial cost.

1 Like

I understand your opinion, and I change my mind to agree with your idea.

As you mentioned, the meaning will be changed, and that is not beautiful. Fortunately, the replacement is doable automatically with tools, so I can still do this.

Thank you for making me understand, bakkot!

2 Likes