使用 JRuby/Jython 实现 Ruby/Python 互操作性?

发布于 2024-08-31 11:54:36 字数 301 浏览 1 评论 0原文

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

我偶然发现了 _为什么今天又是邪恶的..它允许您从 Ruby 代码输出 Python 字节码..基本上允许它们生成相同的字节码..Jython

输出 Java 字节码,JRuby 也是如此..因为它们都编译为相同的字节码,这是否意味着您可以使用 Ruby 中的任何 Python 库以及 Python 中的 Ruby 库?

Quite-probably a silly question, as I don't know much about Java/Jython/JRuby/bytecode, but..

I stumbled across _why's unholy again today.. It allows you to output Python bytecode from Ruby code.. Basically allowing them to produce the same bytecode..

Jython outputs Java bytecode, as does JRuby.. Since these both compile to the same bytecode, does this mean you could potentially use any Python library from Ruby, and Ruby libraries from Python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

遗忘曾经 2024-09-07 11:54:36

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

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

对于 CPython 和 YARV,该平台是 C/POSIX,因此它们可以使用 C 结构、intchar* 和 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 字段。 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(或者更好:他们向 JVM 公开其 MOP 并且都使用相同 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 的运行时(除了常见的嫌疑人,例如 IronRuby , IronPython, IronJS 和 IronScheme 现在还包括 C# 4 和 Visual Basic.NET 10) 几乎可以无缝地相互操作。

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

No, that won't work. At least not the way you think it would.

Interoperability between Jython and JRuby works the same way as between CPython and YARV: they both run on the same platform, so they can communicate with each other using that platform.

In the case of CPython and YARV, that platform is C/POSIX, so they can communicate with each other using C structs, ints, char*s and C function calls. In the case of Jython and JRuby, that platform is the JVM, so they can communicate with each other using JVM objects, JVM classes, JVM interfaces, JVM types and JVM methods.

In both cases, those platform primitives look nothing like Python or Ruby objects.

To JRuby, Jython is just yet another Java program. To Jython, JRuby is just another Java program.

For example: in Ruby, you can add, remove and redefine methods dynamically at any moment. On the JVM, the smallest unit of code that can be dynamically added and removed is a class. So, a Ruby method is actually not represented as a Java method. It is represented as a Java class. And logically, a Ruby object with a couple of methods is represented as a Java object with no methods, just a Dictionary<String, RubyMethod> field. IOW: it's totally unusable from Java, and, since from JRuby's point of view Jython is just Java, it's also unusable from Jython.

Now, there are ways to make this a little bit better. You could use actual Java types to communicate between the two – both implementations have great interoperability with Java. So, instead of passing a Ruby hash to Python or a Python dictionary to Ruby, you would use a Java Map from both Ruby and Python. But note that this requires that both your Ruby and Python code are specifically written to work on the JVM. IOW: you cannot just use any Python or Ruby library you find on the web, which is what you are asking about.

Another possibility is the one mentioned by @duncan in his answer: embed Jython or JRuby as a scripting engine into your Ruby or Python application. But again, this doesn't really answer your question about using arbitrary Python libraries from Ruby or vice versa.

So, what is the problem here?

The problem is that in order for the two runtimes to communicate, they need to speak the same "language". And in this particular case, the only language that the two runtimes have in common, is Java, or rather a severely crippled subset of Java.

So, we need to find a common language. One way to define such a language would be for both runtimes to understand each other's Meta-Object Protocol (MOP).

A MOP is basically an object model for the language's object model. Um, that's confusing because we use the word "object model" to mean two different things. Let me rephrase that:

A MOP is basically a domain model for the language's object system. Just like a domain model for a banking system contains objects that represent real-world customers, accounts, balances, ledgers and so on, and methods that represent real-world actions like money transfers, withdrawals and so on, a MOP contains objects that represent language classes, methods, variables, objects and methods that represent language actions like looking up a variable, calling a method, inheriting from a class, constructing an instance of a class.

Normally, every runtime keeps its MOP private, and every runtime has its own MOP.

If JRuby and Jython exposed their MOPs to each other and understood each other's MOPs (or, even better yet: they exposed their MOPs to the JVM and both used the same MOP), then you could pass one of those crazy JRuby method bags to Jython, and it would know how to find the methods that belong to that object and how to call them, because it can just ask JRuby's MOP how to do it.

There is actually a project to create just such a MOP for the JVM: the dynalang MOP is a project for a shared, standardized MOP for dynamic languages running on the JVM. It was created by Attila Szegedi, the maintainer of the Mozilla Rhino ECMAScript engine. At the moment, none of the big language implementations uses it, but there is collaboration going on between at least Rhino, JRuby, Jython and Groovy to make sure that dynalang is generic enough that it can support all of the different language's object models.

If you want a sneak peek at what a world with such a shared MOP would look like, you can take a look at Microsoft's Dynamic Language Runtime (DLR). The DLR contains just such a MOP and all runtimes which support the DLR (which, in addition to the usual suspects such as IronRuby, IronPython, IronJS and IronScheme now also includes C# 4 and Visual Basic.NET 10) can almost seamlessly interoperate with each other.

Another similar platform is the Parrot Virtual Machine, which was specifically designed to allow multiple dynamic languages to interoperate on the same runtime platform. There are implementations of Python (Pynie) and Ruby (Cardinal) available, but especially Cardinal is still very far from being even a remotely complete Ruby implementation.

有两种方法可以做到这一点。两者都提供静态编译代码并从脚本生成真正的 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​​ stdlib 导出到 python 解释器。您需要提前将 ruby​​ 的 stdlib 预编译为字节码。

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

There are two ways to do it. Both offer the ability to statically compile code and produce a real Java class from the script. Jython AFAIK in this case generates Java source code and then calls javac, via an jythonc script. But this requires compilation.

For both interpreters, you can call Java code from scripts, and you can embed the interpreter in a Java application.

For example, to call Java from Python:

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

To embed JRuby interpreter in Java, you can do (note, there is a JSR223 based way too, this is the core one):

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();
    }

You could do the same from Jyton (I guess you would need to give the jruby paths correctly):

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

The same can be done the other way around.

You won't get the whole ruby stdlib exported to the python interpreter by doing an import. You would need to precompile ruby's stdlib to bytecode in advance.

However with the technique described above, and adding a couple of helper scripts and defined interfaces, you can bridge specific functionality from one language to the other.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文