通过转译器在 Javascript 中实现运算符重载
对于我们中的一些人来说,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 编译器可以在类型为数字时优化掉额外的缺陷。
有想法吗?
One of the problems, for some of us, with Javascript is the lack of operator overloading. This makes writing numeric libraries awkward. For instance, we might want to write something like:
var a = new BigInteger(5);
var b = new BigInteger(10);
var c = a + b;
A possible solution is to transpile a language with operator overloading to Javascript. While feasible -- by replacing operators by function calls and type checks -- the consensus seems to be that this is impossible without killing performance. CoffeeScript has rejected the idea for this reason:
https://github.com/jashkenas/coffee-script/issues/846
But are there really no clever solutions?
For instance, it might be possible hoist type checks out of tight loops or to use some other pipeline where modern JS compilers can optimize away added cruft when the types are numeric.
Ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您真的确定需要您的大数字可以被使用普通数字(使用传统运算符)编写的旧函数使用吗?如果您只是为了自己的方便而需要对您放弃控制的函数进行重载,那么您可以通过对 bignum 使用不同的自定义运算符来实现。
例如,您可以编写一个编译器来安全地转换
为
,或者,如果您想要自动转换...
我真的不认为您能够在没有大麻烦的情况下强制重载现有实现。虽然理论上您可以将所有出现的 + 替换为 <+>等等,当前的 Javascript 实现并未为此进行优化,我什至不想开始思考如果您尝试将 bignum 传递给底层的本机 C++ 函数之一会发生什么。
编辑:不需要重写基本整数类是这里的重点(请注意在您提供的链接中,重写是该人想要的第一件事......)。我不认为你能够找到某种“神奇”的优化,因为你无法控制客户端正在使用众多 JS 实现中的哪一个。
如果您真的不喜欢像 <+> 这样的自定义运算符;区分普通 + 运算符(你不应该干涉)和花哨的 + 运算符(你想要做 bignum 的东西)的唯一方法是在 Javascript 上强制使用某种临时类型系统,也许通过注释、自定义语法或(如评论中提到的)匈牙利表示法。在我看来,仅仅选择一个你不那么讨厌的自定义操作员名称就不会那么黑客化了。
Are you really sure you need your big numbers to be useable by old functions written with normal numbers in mind (that use the traditional operators)? If you only need the overloading for your own convenience on functions you cave control over you might be able to get by by using a different, custom operator for bignums.
For example, you could write a compiler to safely convert
into
or perhaps, if you want automatic conversions...
I don't really see you being able to force overloading on an existing implementation without a big hassle. While you could teoretically replace all occurences of + with <+> and so on, current Javascript implementations are not optimized for this and I don't even want to start thinking what would happen if you tried to pass a bignum to one of the native C++ functions that are under the hood.
edit: Not needing to override the base integer class is the important point here (note how in the link you gave, overriding is the first thing the guy wants...). I don't think you will be able to find some kind "magic" optimization though as you have no control over which of the many JS implementations is being used by the client.
If you really don't like a custom operator like <+> the only way to distinguish a normal + operator (you shoudln't meddle with) from a fancy + operator (you want to do bignum stuff with) would be forcing some kind of ad-hoc typing system on top of Javascript, perhaps via comments, custom syntax or (as mentioned in a comment) hungarian notation. Just settling for a custom operator name you hate less would be less hackish, IMO.
看看 Scala 如何实现运算符重载:
他们定义每个运算符都是对对象的方法调用,所以你的例子是:
如果你停在这里,你可以简单地实现方法重载,函数必须检查传递的值参数。如果您想开发更好的解决方案,请阅读 Odersky 的《Scala 编程》一书,并花一些时间阅读他们如何解决问题的所有想法(这是一个非常好的解决方案!)
Have a look how Scala implemented Operator Overloading:
They defined that every operator is a method call on an object, so your example would be:
If you stop here, you could trivially implement method overload, the function would have to check the values passed by param. If you want to develop a better solution take Odersky's Programing in Scala book and some time to read all their ideas how they've solved the problem (which is a very nice solution!)
解决性能下降问题的一种可能选择是使用 AST 转换并将每个运算符转换为函数,例如
a * b
=>a.multiply(b)
。对于性能敏感代码、瓶颈的罕见情况,提示编译器不应该进行这种转换,类似于 CoffeeScript 语法发出原始 JS 的方式。
One possible option to address performance degradation, could be to use AST transformation and transform every operator to function, like
a * b
=>a.multiply(b)
.And for rare cases for performance sensitive code, bottleneck, hint compiler that it shouldn't do that transformation, similar to how CoffeeScript syntax to emit raw JS.