如果要在 Javascript 引擎之上(在浏览器中或在独立的 V8 或 Spidermonkey 之上)实现 Ruby,那么 Ruby 和 JS 对象模型之间的关键阻抗不匹配会是什么?
3 回答
最直接的一个显然是 ECMAScript 是基于原型的,而 Ruby 是基于类加混合的。此外,在 Ruby 中,封装是用对象完成的,而在 ECMAScript 中则是用闭包完成的。
然而,我的猜测是 Ruby 的控制流构造将成为比其对象模型更大的障碍。毕竟,James Coglan 的 JS.Class 基本上是 Ruby 的对象模型在 ECMAScript 中的实现,它并没有那么大。
ECMAScript 只是缺少在其之上构建您自己的控制流结构所需的工具。通常,您需要GOTO
, 延续或适当的尾调用。如果你有其中之一,你可以轻松地实现其他所有东西:异常、循环、开关、线程、Fiber
s、生成器、协程……你可以命名它。
但是 ECMAScript 没有它们(并且有充分的理由,至少在 的情况下GOTO
)。ECMAScript 中唯一强大到能够在其之上构建其他结构的控制流结构是异常。不幸的是,这些速度很慢。(尽管如此,它们已被用作实现基础,例如在 Microsoft Live Labs Volta 编译器中,它使用 ECMAScript 异常来实现 .NET 异常、迭代器、生成器甚至线程。)
所以,如果不是一个完整的解释器(如 HotRuby 的情况),基本上你至少要实现自己的调用堆栈,执行全局 CPS 转换或类似的东西。
基本上,您想要从运行在 ECMAScript 之上的 Ruby 引擎得到的是
- RubySpec 的忠实实现(特别是控制流结构,如线程、纤程、
throw
/catch
、异常等), - 性能和
- 与 ECMAScript 紧密集成(即能够在两种语言之间来回传递对象和调用方法)。
不幸的是,当你不得不求助于管理自己的堆栈、进行 CPS 转换、构建异常等技巧时……事实证明,你只能选择三个目标中的两个。
- Ruby 具有局部变量的块级作用域,JavaScript 具有函数级作用域
- 简单地使用 JavaScript 的原型继承来实现 Ruby 的继承 + mixins 可能会出现问题
- Ruby 对方法/lambda 调用的数量检查,比 JavaScript 的许可传递更严格
- Ruby 有真实的、强制的常量;JavaScript 可能不会(取决于解释器使用的版本)
- 类变量(呃)在 JaveScript 中没有等价物,因此需要特殊处理
- Ruby 的核心有绿色线程,JavaScript 没有
JavaScript 是图灵完备的,所以理论上你可以实现任何东西,包括其中的其他编程语言。实现(JavaScript)和目标语言(Ruby)有多么不同并不重要。Ruby 和 C 等语言之间的阻抗不匹配是巨大的,而 Ruby、Python、Perl 和 JavaScript 本身都是用 C 实现的。
在 JavaScript 中实现 Ruby 应该比在较低级别的语言中实现容易几个数量级。对你有利的是,你有很多 Ruby 和 Ruby 的标准库是用 Ruby 本身编写的,所以一旦你有了一个基本的解释器,事情应该会越来越走下坡路。
在 JavaScript 中实现一个高效的Ruby 解释器可能更难,但它仍然是可能的。您最终可能会将 Ruby 翻译成 JavaScript,以便可以使用出色的优化器。
因此,不要考虑 Ruby 和 JavaScript 之间的差异。看看 Ruby 的标准实现,并考虑如何在 JavaScript 中实现它。