【问题标题】:Using JRuby/Jython for Ruby/Python interoperability?使用 JRuby/Jython 实现 Ruby/Python 互操作性?
【发布时间】:2011-02-14 17:30:01
【问题描述】:

很可能是一个愚蠢的问题,因为我对 Java/Jython/JRuby/字节码了解不多,但是..

我今天再次偶然发现_why's unholy..它允许您从 Ruby 代码输出 Python 字节码..基本上允许它们产生相同的字节码..

Jython 输出 Java 字节码,JRuby 也是如此。由于它们都编译为相同的字节码,这是否意味着您可以使用任何来自 Ruby 的 Python 库和来自 Python 的 Ruby 库?

【问题讨论】:

  • +1 回答一个有趣的问题...
  • 顺便说一句:在邪恶的自述文件末尾提到的“运行所有语言的神话 VM”,我在回答中提到的 Parrot VM。值得庆幸的是,它现在不再是神话:1.0.0 的大版本是一年多以前的事了,从那时起,Parrot 团队像发条一样每月发布一个稳定版本,两周前(目前)达到了 2.3.0 .当然,这并不意味着每种语言实际上都有一个编译器(特别是,Cardinal Ruby 编译器远未准备好生产),只是 VM 存在且稳定.

标签: python ruby jruby jython bytecode


【解决方案1】:

不,这行不通。至少不是你想象的那样。

Jython 和 JRuby 之间的互操作性与 CPython 和 YARV 之间的互操作性工作方式相同:它们都运行在同一个平台上,因此它们可以使用该平台相互通信。

对于 CPython 和 YARV,该平台是 C/POSIX,因此它们可以使用 C 结构、ints、char*s 和 C 函数调用相互通信。对于 Jython 和 JRuby,该平台就是 JVM,因此它们可以使用 JVM 对象、JVM 类、JVM 接口、JVM 类型和 JVM 方法相互通信。

在这两种情况下,这些平台原语看起来一点也不像 Python 或 Ruby 对象。

对于 JRuby,Jython 只是另一个 Java 程序。对于 Jython,JRuby 只是另一个 Java 程序。

例如:在 Ruby 中,您可以随时动态地添加、删除和重新定义方法。在JVM上,可以动态添加和删除的最小代码单元是一个类。因此,Ruby 方法实际上并不表示为 Java 方法。它表示为 Java 。从逻辑上讲,具有几个方法的 Ruby 对象表示为没有方法的 Java 对象,只有一个 Dictionary<String, RubyMethod> 字段。 IOW:它在 Java 中完全不可用,而且,因为从 JRuby 的角度来看,Jython 只是 Java,所以它也不能从 Jython 中使用。

现在, 种方法可以让这一切变得更好。您可以使用实际的 Java 类型在两者之间进行通信——这两种实现都与 Java 具有很好的互操作性。因此,您可以使用 Ruby 和 Python 中的 Java Map,而不是将 Ruby 哈希传递给 Python 或将 Python 字典传递给 Ruby。但请注意,这要求您的 Ruby 和 Python 代码是专门为在 JVM 上工作而编写的。 IOW:你不能只使用你在网上找到的任何 Python 或 Ruby 库,这就是你要问的。

@duncan 在他的回答中提到了另一种可能性:将 Jython 或 JRuby 作为脚本引擎嵌入到您的 Ruby 或 Python 应用程序中。但同样,这并不能真正回答您关于使用 Ruby 中的任意 Python 库的问题,反之亦然。

那么,这里有什么问题?

问题在于,为了让两个运行时进行通信,它们需要使用相同的“语言”。在这种特殊情况下,两个运行时的唯一共同语言是 Java,或者说是 Java 的一个严重残缺的子集。

所以,我们需要找到一种共同语言。定义这种语言的一种方法是让两个运行时都了解彼此的元对象协议 (MOP)。

MOP 基本上是语言对象模型的对象模型。嗯,这很令人困惑,因为我们使用“对象模型”这个词来表示两个不同的东西。让我换个说法:

MOP 基本上是语言对象系统的领域模型。就像银行系统的域模型包含代表现实世界客户、账户、余额、分类帐等的对象,以及代表现实世界行动(如汇款、取款等)的方法,MOP 包含代表的对象表示语言操作的语言类、方法、变量、对象和方法,例如查找变量、调用方法、从类继承、构造类的实例。

通常,每个运行时都将其 MOP 保持为私有,并且每个运行时都有自己的 MOP。

如果 JRuby 和 Jython 彼此公开他们的 MOP 并理解彼此的 MOP(或者,更好的是:他们将自己的 MOP 公开给 JVM 并且都使用了相同的 MOP),那么您可以将其中一个疯狂的 JRuby 方法包传递给 Jython,它就会知道如何找到属于该对象的方法以及如何调用它们,因为它可以询问 JRuby 的 MOP 是如何做到的。

实际上有一个项目可以为 JVM 创建这样的 MOP:dynalang MOP 是一个用于在 JVM 上运行的动态语言的共享标准化 MOP 项目。它由 Mozilla Rhino ECMAScript 引擎的维护者 Attila Szegedi 创建。目前,没有一个大型语言实现使用它,但至少 Rhino、JRuby、Jython 和 Groovy 之间正在进行协作,以确保 dynalang 足够通用,可以支持所有不同语言的对象模型。

如果您想先睹为快,了解具有这种共享 MOP 的世界会是什么样子,您可以查看 Microsoft 的动态语言运行时 (DLR)。 DLR 仅包含这样一个 MOP 和支持 DLR 的所有运行时(除了常见的问题,例如 IronRubyIronPythonIronJSIronScheme,现在还包括 C# 4 和 Visual Basic.NET 10) 几乎可以无缝地相互操作。

另一个类似的平台是Parrot Virtual Machine,它专门设计用于允许多种动态语言在同一个运行时平台上互操作。有可用的 Python (Pynie) 和 Ruby (Cardinal) 的实现,但尤其是 Cardinal 距离远程完整的 Ruby 实现还有很长的路要走。

【讨论】:

    【解决方案2】:

    有两种方法可以做到这一点。两者都提供了静态编译代码和从脚本生成真正的 Java 类的能力。在这种情况下,Jython AFAIK 生成 Java 源代码,然后通过 jythonc 脚本调用 javac。但这需要编译。

    对于这两种解释器,您都可以从脚本中调用 Java 代码,并且可以将解释器嵌入到 Java 应用程序中。

    例如,从 Python 调用 Java:

    >>> from java.util import Random
    >>> r = Random()
    >>> r.nextInt()
    501203849
    

    要在Java中嵌入JRuby解释器,你可以这样做(注意,也有一种基于JSR223的方式,这是核心方式):

    package vanilla;
    
    import org.jruby.embed.ScriptingContainer;
    
    public class HelloWorld {
    
        private HelloWorld() {
            ScriptingContainer container = new ScriptingContainer();
            container.runScriptlet("puts Hello world");
        }
    
        public static void main(String[] args) {
            new HelloWorld();
        }
    

    你可以从 Jyton 做同样的事情(我猜你需要正确地给出 jruby 路径):

    import org.jruby.embed.ScriptingContainer
    container = ScriptingContainer()
    container.runScriptlet("puts Hello world")
    

    反之亦然。

    您不会通过导入将整个 ruby​​ 标准库导出到 python 解释器。您需要提前将 ruby​​ 的 stdlib 预编译为字节码。

    但是,通过上述技术,并添加几个帮助脚本和定义的接口,您可以将特定功能从一种语言连接到另一种语言。

    【讨论】:

      猜你喜欢
      • 2011-10-26
      • 2021-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      • 2011-09-29
      相关资源
      最近更新 更多