Python application running on GraalVM and Polyglotting with JavaScript, R, Ruby and Java

0

GraalVM is among other things a polyglot language runtime. It can run applications written in many languages – JVM languages like Java, Scala, Groovy and Kotlin as well as non-JVM language such as Python, R, Ruby, JavaScript and LLVM. GraalVM also allows applications in any of these languages to execute code snippets written in any of the other languages it supports. It is like the cab driver that can speak many languages and also is perfectly capable of understanding you when you start interjecting fragments of different languages into your attempt to explain where you want to go.

In this article, I will take a brief look at the polyglot interaction on GraalVM from Python with other languages, specifically Java, JavaScript and R (only scratching the surface). The Python implementation on GraalVM is brand new at this stage (October 2019) and has limited supported for many language features. It is not yet suitable for production usage. As stated on the GraalVM site:

GraalVM’s implementation of Python is in the early stages of development. A primary goal is to support SciPy and its constituent libraries, but we have a long way to go there. At this point, the Python implementation is made available for experimentation and curious end-users. GraalVM currently aims to be compatible with Python 3.7, but it is a long way from there, and it is very likely that any Python program that requires any imports at all will hit something unsupported.

The funny thing is that when you call out to Java, JavaScript and R, the code is interpreted by more mature engines: Java and JavaScript production applications are running on GraalVM today.

image

A great visualization of what running Python on GraalVM means in terms of underlying components is shown below – I have ‘borrowed’ this illustration from the article Introduction to the Python implementation for GraalVM by Franzi Geiger on Medium (August 2019) Python code is parsed into a Truffle Abstract Syntax Tree represented in Java Byte Code. Any non-JVM language running GraalVM is parsed into such an AST. GraalVM’s runtime knows how to run these trees. And the polyglot glue in GraalVM knows how to merge trees before executing them.

image

The sample Python application demonstrates a number of aspects of polyglot interaction from Python:

  • how to evaluate code snippets in various languages (Java, R, JavaScript,Ruby)
  • how to execute a function object returned from another language
  • how to put objects – data objects and functions – into the Polyglot map that lives between all polyglot languages executed on GraalVM
  • how to retrieve objects from the Polyglot map – read and write them or execute them

R, Ruby and JavaScript from Python

image

In each case, a snippet of code is evaluated at runtime and the result of the evaluation against the proper language engine is returned to the Python program, ready for inspection and further manipulation.

Java from Python

image

 

Java interoperability works a little differently from the polyglot interaction with non-JVM (or Truffle) languages. Java Classes – custom and 3rd party libraries – are provided on the classpath parameter passed to graalpython. All standard Java 8 APIs are available at all times. image

JavaScript from Python – leveraging the Polyglot Map

In this snippet, a variable title is put in the Polyglot map with the export_value function under the key “title”. Next, a JavaScript snippet is evaluated. This results in the creation of an anonymous function that subsequently is returned to Python. In Python, the function is printed and executed. The result is stored in variable msg and finally the value of that function is printed. image

image

The output of running this snippet is shown here. The second line is produced from within the JavaScript function. It shows that the JavaScript code successfully imported the title from the Polyglot Map.

image

JavaScript and R from Python – transferring functions across language barriers

The next snippet is even more convoluted: a JavaScript snippet is evaluated. It exports a function definition into the Polyglot Map under the key squared. The function is imported from the Map in Python – and executed from Python. Subsequently, a snippet of R code is evaluated; this snippet too creates a function that it evaluates to. In this snippet, the R code imports function squared from the Polyglot Map (put there by the JavaScript snippet) and executes it. It also imports title from the map and prints it to the output. The function returned from the R snippet is executed in Python (and indirectly performs what was defined in JavaScript).

image

image

The output from this specific Python code fragment

image

Here is the code for the complete application:

import polyglot
import java

array = polyglot.eval(language="js", string="[1,2,42,4]")
print("JavaScript ",array[2])

array = polyglot.eval(language="R", string="c(1L,2L,42L,4L)")
print("R ",array[1])

array = java.type("int[]")(4)
array[2] = 42
print("Java", array[2])

array = polyglot.eval(language="ruby", string="[1,2,42,4]")
print("Ruby", array[2])

title = "Polyglot Programming"
polyglot.export_value (title, "title" )

func = polyglot.eval(language="js"
       , string="(function(name) { print(`Title from polyglot ${Polyglot.import('title')}`);return `Hello ${name}, welcome to the world of JavaScript`; })")
print(func)
msg = func("Hank")
print("The result of invoking the function produced by the JavaScript function: ",msg)

polyglot.eval(language="js", string="Polyglot.export('key','value');")
value = polyglot.import_value ("key" )
print("Imported key from polyglot",value)

title = "Polyglot Programming"
polyglot.export_value (title, "title" )

# have JS create a function and store it in Polyglot
polyglot.eval(language="js", string="Polyglot.export('squared', x => {print(x); return x * x})")
js_squared = polyglot.import_value('squared')
result = js_squared(22)
print("The result of invoking function squared imported from polyglot",result)

# have R create a function, leveraing the function squared stored from JS in polyglot
fnc = polyglot.eval(string="""function(input) {
    squared <- import('squared')
    result <- squared(input)
    print( paste('Imported title from Polyglot: ', import('title')))
    result
}""", language="R")

# invoke the function returned from R, leveraging JS
print("squared from R using function from JS",fnc(5))

To run the entire application on GraalVM:

graalpython --polyglot --jvm ./python_polyglot.py

GraalPython is the Python runtime execution engine on GraalVM. The polyglot setting indicates that polyglot language interoperability is active and the jvm switch is currently required for using the JVM as execution platform: To interoperate with other languages, we had to supply the –jvm argument above. This instructs the launcher to run on the JVM instead of in the Native Image mode – you will notice a longer startup time than with the native image graalpython execution engine (substantially longer).

If we want to invoke Java Objects defined outside the Java 8 APIs, we have to provide them to Graalpython by specifying the –vm.cp=<colon separated list of JAR Files, directories> command line option.

The output of running the application:

image

Resources

GitHub Repository with sources for this article: https://github.com/AMIS-Services/jfall2019-graalvm

GraalVM Docs on Graal Python – https://www.graalvm.org/docs/reference-manual/languages/python/

GraalVM Docs – interoperability from Python – https://www.graalvm.org/docs/reference-manual/languages/python/#interoperability

GraalVM Docs – Polyglot including Python as target and as starting language: https://www.graalvm.org/docs/reference-manual/polyglot/

GitHub Home of GraalPython – https://github.com/graalvm/graalpython

Introduction to the Python implementation for GraalVM – https://medium.com/graalvm/how-to-contribute-to-graalpython-7fd304fe8bb9

JavaDocs for GraalVM Polyglot – https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/package-summary.html

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director and Oracle Developer Champion. Solution architect and developer on diverse areas including SQL, JavaScript, Kubernetes & Docker, Machine Learning, Java, SOA and microservices, events in various shapes and forms and many other things. Author of the Oracle Press book Oracle SOA Suite 12c Handbook. Frequent presenter on user groups and community events and conferences such as JavaOne, Oracle Code, CodeOne, NLJUG JFall and Oracle OpenWorld.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.