【问题标题】:What are the key semantic differences between Ruby and JavascriptRuby 和 Javascript 之间的主要语义差异是什么
【发布时间】:2011-07-27 19:28:36
【问题描述】:

如果要在 Javascript 引擎之上(在浏览器中或在独立的 V8 或 Spidermonkey 之上)实现 Ruby,那么 Ruby 和 JS 对象模型之间的关键阻抗不匹配会是什么?

【问题讨论】:

  • 我在查看 SpiderMonkey 跟踪 JIT 的架构时想到了这个问题——它是否也可以作为 Ruby 实现的核心。为浏览器编写 Ruby 也很好(就像 GWT 为 Java 编写的那样)——在这种情况下,我想对可以使用的库和语言特性会有很多限制。
  • 我认为到目前为止(Marc-André Lafortune 在评论中指出的)最大的问题是缺少方法/常量和自动加载功能。未来版本的 Ecmascript 将包含可能允许有效实施的“代理”:wiki.ecmascript.org/doku.php?id=harmony:proxies
  • 实际上,无论 Firefox 4 中的 TraceMonkey 版本是什么,我都非常确定代理存在,我希望其他实现者也能效仿,因为它们对安全性非常有用. (参见,例如 Mark S. Miller 的 SES(安全 ECMAScript)和 Dr. SES(分布式弹性安全 ECMAScript)工作)。
  • TraceMonkey 跟踪 JIT 主要由 nanojit 组成,无论如何它是一个独立于语言的 JIT 编译器,不是吗?如果你想要的只是一个带有跟踪 JIT 的 Ruby 实现,那么真的不需要编译到 ECMAScript,只需将 nanojit 连接到 Rubinius。或者用 PyPy 编写一个 Ruby 实现,它的跟踪 JIT 非常棒。 (顺便说一句,PyPy 有一个 ECMAScript 后端,所以你实际上是用一块石头杀死了两只鸟。更像是 4 只鸟,因为用 PyPy 编写的 Ruby 实现可以在 JVM、.NET 和 ECMAScript 上本地运行。 )
  • @Jörg 感谢 PyPy 的指针 - 这看起来确实是一个有趣的项目。

标签: javascript ruby programming-languages v8 spidermonkey


【解决方案1】:
  1. Ruby 具有局部变量的块级作用域,JavaScript 具有函数级作用域
  2. 仅使用 JavaScript 的原型继承来实现 Ruby 的继承 + mixins 可能会出现问题
  3. Ruby 对方法/lambda 调用的数量检查,比 JavaScript 的许可传递更严格
  4. Ruby 有真正的强制常量; JavaScript 可能不会(取决于解释器使用的版本)
  5. 类变量(呃)在 JaveScript 中没有等效项,因此需要特殊处理
  6. Ruby 的核心有绿色线程,而 JavaScript 没有

【讨论】:

  • 好名单。我肯定会添加像method_missingconst_missingautoload 这样的钩子的兼容性也意味着必须包装每个方法调用或常量查找(比如myobject._call_method_("foo", ..)
  • 模式 function(){..}()(即立即调用内联 anon 函数)在 JS 世界中并不陌生——这将允许模拟块作用域。
  • 向 JS 对象添加 mixin 需要将方法从 mixin 复制到对象中,这是有代价的——还有什么比这更重要的吗?
  • 我知道 JRuby 使用本地操作系统线程而不是绿色线程 - 这会导致问题吗?在浏览器中,线程的要求并不高,或者需要显式使用 Web Worker,所以这可能不是一个大问题。
  • @Marc-André - “缺失”的处理程序听起来确实是最大的问题。他们需要在调用或使用之前对每个引用进行空值检查,这将是昂贵的。感谢您指出这一点。
【解决方案2】:

最直接的一个显然是 ECMAScript 是基于原型的,而 Ruby 是基于 class-plus-mixin 的。此外,在 Ruby 中,封装是用对象完成的,而在 ECMAScript 中,则是用闭包完成的。

但是,我的猜测是 Ruby 的控制流构造将比其对象模型面临更大的障碍。毕竟James Coglan's JS.Class基本上是 Ruby 的对象模型在 ECMAScript 中的一个实现,并没有那么大。

ECMAScript 只是缺少在其之上构建您自己的控制流结构所需的工具。通常,您需要GOTO、延续或适当的尾调用。如果您拥有其中之一,则可以轻松实现其他所有内容:异常、循环、开关、线程、Fibers、生成器、协程……您可以命名它。

但是 ECMAScript 没有它们(并且有充分的理由,至少在 GOTO 的情况下)。 ECMAScript 中唯一强大到能够在其之上构建其他结构的控制流结构是异常。不幸的是,这些速度很慢。 (尽管如此,它们被用作实现基础,例如在 Microsoft Live Labs Volta 编译器中,它使用 ECMAScript 异常来实现 .NET 异常、迭代器、生成器甚至线程。)

所以,如果不是整个解释器(如 HotRuby 的情况),基本上你至少要实现自己的调用堆栈,执行全局 CPS 转换或类似的东西。

基本上,您想要在 ECMAScript 之上运行的 Ruby 引擎是

  1. RubySpec 的忠实实现(特别是控制流构造,如线程、纤程、throw/catch、异常等),
  2. 性能和
  3. 与 ECMAScript 紧密集成(即能够在两种语言之间来回传递对象和调用方法)。

不幸的是,当您不得不求助于管理自己的堆栈、进行 CPS 转换、在异常之上构建等技巧时……事实证明,您只能选择三个目标中的两个。

【讨论】:

  • 讨厌 goto 是怎么回事?
  • @dsimcha:你对“仇恨”有一些非常奇怪的定义。
  • 您可能需要在对象之间复制一些方法来模拟混合。感谢您对生成器等的提醒 - 我会考虑如何毫无例外地模拟这些。
  • 我不认为基于对象和基于闭包的封装之间的差异很大。在 JS 世界中,有很多技巧可以实现似乎适用的私有方法和属性。
【解决方案3】:

JavaScript 是图灵完备的,所以理论上你可以实现任何东西,包括其中的其他编程语言。 实现 (JavaScript) 和目标语言 (Ruby) 有多么不同并不重要。 Ruby 和 C 等语言之间的阻抗不匹配是巨大的,而 Ruby、Python、Perl 和 JavaScript 本身都是用 C 实现的。

在 JavaScript 中实现 Ruby 应该比在低级语言中实现要容易几个数量级。对你来说,你有很多 Ruby 和 Ruby 的标准库是用 Ruby 本身编写的,所以一旦你有了一个基本的解释器,事情应该会越来越走下坡路。

在 JavaScript 中实现一个高效的 Ruby 解释器可能更难,但它仍然是可能的。您最终可能会将 Ruby 翻译成 JavaScript,以便可以使用出色的优化器。

所以,不要考虑 Ruby 和 JavaScript 之间的区别。看看 Ruby 的标准实现,并思考如何在 JavaScript 中实现 that

【讨论】:

  • 感谢您的回答 - 我正在考虑如何从现有的 Ruby 实现交叉编译到 Javascript,而不是在浏览器中实现完整的 Ruby 解释器/REPL。
  • @Nick 交叉编译需要解释器的大部分工作,所以以同样的方式处理它。看看在 C 和/或 Java 中实现 Ruby 的运行时支持,并考虑如何在 JavaScript 中实现它。不是翻译代码,而是找出在运行时支持 Ruby 所需的数据结构和功能。
猜你喜欢
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 2011-06-05
  • 2022-01-03
  • 2016-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多