Polyglot Programming using GraalVM in Kotlin
The meaning of the word polyglot is knowing or using several languages. In this article, we'll see what that means from a programming perspective and create a hello world program demonstrating the concept.
Git repository for this demo: https://github.com/priyansh-07/polyglotKotlinJs
Polyglot Program
Simply put, a polyglot program is a program which consists of multiple programming languages and is executed in a single VM while also passing values to each other. This is done so that we can leverage the advantages of multiple languages in a single application.
What is GraalVM?
GraalVM is a JDK which optimizes the performance of JVM languages and provides runtimes for other languages such JavaScript, Python, Ruby, R and WASM at the time of writing this article.
Java's Polyglot API for GraalVM
This article uses GraalVM's Polyglot API to demonstrate how we can execute JavaScript and Java code on the same VM.
GraalVM provides an extensive API in java for Polyglot execution of code, but this article will cover only a couple of them.
Context
: AContext
is responsible to execute guest language code and maintain the runtime environment for all the installed & permitted languages.Value
: When aContext
executes a guest language code, it returns the value returned by that code as aValue
. This class has some methods to determine the datatypes of the value returned and to cast those values in the host language data types.
Pre-requisites
In this demo, we will be using certain tools but feel free to use their alternatives as a matter of personal preference.
Language: Kotlin
IDE: Intellij
Build tool: Gradle
Test Framework: Spock
Setup
Create a new Gradle project in Intellij and select Kotlin/JVM
Name the project
Set up the
build.gradle
Add a plugin for groovy for tests
Add dependencies for graalvm js, spock and groovy
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.6.10'
id 'groovy'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation group: 'org.graalvm.js', name: 'js', version: '22.3.1'
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
implementation 'org.apache.groovy:groovy:4.0.11'
}
test {
useJUnitPlatform()
}
Write a failing test case
Following the practices described by Uncle Bob, we will be following a test-driven approach and the first thing to do is to write a failing test case.
package org.example.polyglot
import org.graalvm.polyglot.Value
import spock.lang.Specification
class JsPolyglotSpec extends Specification {
def "test the value returned by a js function"() {
given:
String jsFunction = """
|function square(x) {
| return x * x;
|}""".stripMargin()
String jsFunctionCall = "square(2)"
when:
new JsPolyglot.execute(jsFunction)
Value value = JsPolyglot.execute(jsFunctionCall)
then:
value.isNumber()
value.asInt() == 4
}
}
First, we define a JavaScript function ,
jsFunction,
and a call to that function,jsFunctionCall
, in thegiven
block.In the
when
block, we call API to execute the JavaScript code,JsPolyglot.execute()
, and execute thejsFunction
to put it into the environment so that we can executejsFunctionCall
later.In the
then
block, we assert that theValue
is a Number and it is4.
Note: This should not compile as we have not created the
JsPolyglot
class yet.
Write the API that passes the test
package org.example.polyglot
import org.graalvm.polyglot.Context
import org.graalvm.polyglot.Value
class JsPolyglot {
companion object {
private val context: Context = Context
.newBuilder("js")
.build()
}
fun execute(jsCode: String): Value {
return context.eval("js", jsCode)
}
}
Create a Kotlin class
JsPolyglot
in the same package in the main directory.Create a
Context
object in the companion object of the class so that the context retains the function definition in the environment. We pass"js"
, which is a unique identifier for JavaScript in GraalVM, as an argument to thenewBuilder()
to tell GraalVM that only JavaScript is permitted.In the
execute
method, we call thecontext.eval()
to execute the JavaScript code and return itsValue
. This takes a language identifier and the code to be executed as parameters.
That's it, the test should pass, feel free to fiddle around with the parameter we pass to the square function.
Conclusion
Polyglot programming is an amazing concept which can serve as a tool to creatively solve problems and GraalVM's Java API is a powerful tool that makes it easy to implement.
Subscribe to my newsletter
Read articles from Priyansh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Priyansh
Priyansh
Software developer with a passion for computer science and clean code. I love to design robust and extensible software and share knowledge.