Использование JRuby/Jython для совместимости с Ruby/Python?

Довольно, наверное, глупый вопрос, поскольку я мало знаю о Java/Jython/JRuby/bytecode, но..

Я снова наткнулся на _ почему unholy сегодня. Он позволяет выводить байт-код Python из Ruby-кода. В принципе, позволяет создавать одинаковые байткод..

Jython выводит байт-код Java, как и JRuby.. Так как эти оба компилируются в один и тот же байт-код, означает ли это, что вы могли бы использовать любую библиотеку Python из Ruby и библиотеки Ruby из Python?

Ответ 1

Нет, это не сработает. По крайней мере, не так, как вы думаете.

Взаимодействие между Jython и JRuby работает так же, как между CPython и YARV: они оба работают на одной платформе, поэтому они могут общаться друг с другом с помощью этой платформы.

В случае CPython и YARV эта платформа является C/POSIX, поэтому они могут связываться друг с другом с помощью C-структур, int s, char* и вызовов функций 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 или словарь Python для Ruby, вы должны использовать Java Map из Ruby и Python. Но учтите, что это требует, чтобы и ваш Ruby, и Python-код были специально написаны для работы с JVM. IOW: вы не можете просто использовать любую библиотеку Python или Ruby, которую вы найдете в Интернете, о чем вы просите.

Еще одна возможность - это тот, о котором упоминал @duncan в своем ответе: встроить Jython или JRuby в качестве механизма сценариев в ваше приложение Ruby или Python. Но опять же, это на самом деле не отвечает на ваш вопрос об использовании произвольных библиотек Python из Ruby или наоборот.

Итак, в чем проблема?

Проблема заключается в том, что для того, чтобы обе среды взаимодействия связывались, им нужно говорить на одном и том же "языке". И в этом конкретном случае, единственным языком, с которым связаны два времени выполнения, является Java или, скорее, сильно искалеченное подмножество Java.

Итак, нам нужно найти общий язык. Одним из способов определения такого языка было бы для обоих сред выполнения понимать друг друга Протокол метаобъектов (MOP).

MOP - это в основном объектная модель для объектной модели языка. Ум, это сбивает с толку, потому что мы используем слово "объектная модель" для обозначения двух разных вещей. Позвольте мне перефразировать это:

MOP - это в основном модель домена для системы языковых объектов. Так же, как модель домена для банковской системы содержит объекты, которые представляют клиентов реального мира, учетные записи, балансы, бухгалтерские книги и т.д., А также методы, которые представляют реальные действия, такие как денежные переводы, снятие средств и т.д., MOP содержит объекты, которые представляют языковые классы, методы, переменные, объекты и методы, которые представляют языковые действия, такие как поиск переменной, вызов метода, наследующий от класса, построение экземпляра класса.

Обычно каждая среда выполнения сохраняет свой MOP закрытый, и каждая среда выполнения имеет свой собственный MOP.

Если JRuby и Jython разоблачили свои MOP друг другу и поняли друг друга MOP (или еще лучше: они разоблачили свои MOP в JVM и оба использовали один и тот же СС), тогда вы могли бы передать один из этих сумасшедших методов JRuby мешки в Jython, и он будет знать, как найти методы, принадлежащие этому объекту, и как их называть, потому что он может просто спросить JRuby MOP, как это сделать.

На самом деле существует проект создания такого MOP для JVM: dynalang MOP - это проект для общего стандартизованного MOP для динамические языки, запущенные на JVM. Он был создан Attila Szegedi, сопровождающим движком Mozilla Rhino ECMAScript. На данный момент ни одна из реализаций большого языка не использует его, но существует сотрудничество между по крайней мере Rhino, JRuby, Jython и Groovy, чтобы убедиться, что dynalang достаточно общий, чтобы он поддерживал все различные языковые модели объектов.

Если вы хотите, чтобы выглядел мир с таким общим MOP, вы можете взглянуть на Microsoft Dynamic Language Runtime (DLR). DLR содержит только такую ​​MOP и все промежутки времени, которые поддерживают DLR (который помимо обычных подозреваемых, таких как IronRuby, IronPython, IronJS и IronScheme теперь также включает в себя С# 4 и Visual Basic.NET 10) может почти беспрепятственно взаимодействовать друг с другом.

Еще одна подобная платформа - Parrot Virtual Machine, которая была специально разработана, чтобы позволить нескольким динамическим языкам взаимодействовать на одной платформе времени исполнения. Существуют реализации Python (Pynie) и Ruby (Cardinal), но особенно кардинал все еще очень далек от того, чтобы быть даже удаленной реализацией Ruby.

Ответ 2

Есть два способа сделать это. Оба предлагают возможность статически компилировать код и создавать настоящий Java-класс из script. Jython AFAIK в этом случае генерирует исходный код Java, а затем вызывает javac через jythonc script. Но для этого требуется компиляция.

Для обоих интерпретаторов вы можете вызывать код Java из сценариев, и вы можете встроить интерпретатор в Java-приложение.

Например, для вызова Java из Python:

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

Чтобы внедрить интерпретатор JRuby в Java, вы можете это сделать (обратите внимание, что есть также основанный на 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 в байт-код заранее.

Однако с помощью описанной выше методики и добавления нескольких вспомогательных скриптов и определенных интерфейсов вы можете свести конкретную функциональность от одного языка к другому.