通过转译器在Javascript中实现操作符重载

Implementing operator overloading in Javascript via a transpiler

本文关键字:实现 操作符 重载 Javascript      更新时间:2023-09-26

对于我们中的一些人来说,Javascript的一个问题是缺乏操作符重载。这使得编写数字库变得很尴尬。例如,我们可能想要这样写:

var a = new BigInteger(5);
var b = new BigInteger(10);
var c = a + b;

一个可能的解决方案是将带有操作符重载的语言翻译成Javascript。虽然可行——用函数调用和类型检查替换操作符——但共识似乎是,这在不影响性能的情况下是不可能的。CoffeeScript拒绝了这个想法,原因如下:

https://github.com/jashkenas/coffee-script/issues/846

但是真的没有聪明的解决方案吗?

例如,可以将类型检查从紧循环中提升出来,或者使用其他管道,当类型是数字时,现代JS编译器可以优化掉添加的赘物。

想法?

你真的确定你需要你的大数是可用的旧函数写正常的数字在头脑中(使用传统的操作符)?如果您只是为了方便而需要对您控制的函数进行重载,则可以通过使用不同的自定义操作符来处理二进制数。

例如,您可以编写一个编译器来安全地转换
var d = a <+> b <*> c;

var d = (a).add((b).multiply(c));

或者,如果你想要自动转换…

var d = toBignum(a).add(toBignum(b).multiply(toBignum(c)));

我真的不认为你能够在没有大麻烦的情况下对现有的实现强制重载。虽然理论上你可以用<+>等替换所有+的出现,但目前的Javascript实现并没有为此进行优化,我甚至不想开始考虑如果你试图将一个大值传递给底层的本地c++函数会发生什么。


edit:不需要重写基整数类是这里的重点(注意在你给出的链接中,重写是这家伙想要的第一件事…)。我不认为你将能够找到某种"神奇"的优化,尽管你无法控制客户端正在使用的众多JS实现中的哪一个。

如果你真的不喜欢像<+>这样的自定义操作符,区分普通+操作符(你不应该干预)和花哨+操作符(你想做大的东西)的唯一方法是在Javascript之上强制某种特殊的类型系统,可能是通过注释、自定义语法或(如注释中提到的)匈牙利符号。在我看来,选择一个你不太讨厌的自定义操作符名字会显得不那么粗俗。

看看Scala是如何实现运算符重载的:

他们定义了每个操作符都是对对象的方法调用,所以你的例子是:

var c = a["+"](b);

如果停在这里,可以简单地实现方法重载,函数必须检查param传递的值。如果你想开发一个更好的解决方案,请参考Odersky的Scala编程书,花点时间阅读他们如何解决问题的所有想法(这是一个非常好的解决方案!)

解决性能下降的一个可能选择是使用AST转换并将每个操作符转换为功能,如a * b =>a.multiply(b) .

对于性能敏感的代码,瓶颈,提示编译器不应该进行转换,类似于CoffeeScript语法发出原始JS的方式。