Interoperability

GraalVM supports several other programming languages including JavaScript, Ruby, Python, and those that compile to LLVM bitcode. GraalVM’s R runtime provides an API for programming language interoperability that lets you execute code from any other GraalVM-supported language. Note that you must start the R script with --polyglot to have access to other languages.

GraalVM’s R runtime allows the following interoperability primitives:

Use the ?functionName syntax to learn more. The following example demonstrates the interoperability features:

# get an array from Ruby
x <- eval.polyglot('ruby', '[1,2,3]')
print(x[[1]])
# [1] 1

# get a JavaScript object
x <- eval.polyglot(path='r_example.js')
print(x$a)
# [1] "value"

# use R vector in JavaScript
export('robj', c(1,2,3))
eval.polyglot('js', paste0(
    'rvalue = Polyglot.import("robj"); ',
    'console.log("JavaScript: " + rvalue.length);'))
# JavaScript: 3
# NULL -- the return value of eval.polyglot

(Uses r_example.js.)

R vectors are presented as arrays to other languages. This includes single element vectors, e.g., 42L or NA. However, single element vectors that do not contain NA can be typically used in places where the other languages expect a scalar value. An array subscript or similar operation can be used in other languages to access individual elements of an R vector. If the element of the vector is not NA, the actual value is returned as a scalar value, e.g., int. If the element is NA, then a special object that looks like null is returned. The following Ruby code demonstrates this:

vec = Polyglot.eval("R", "c(NA, 42)")
p vec[0].nil?
# true
p vec[1]
# 42

vec = Polyglot.eval("R", "42")
p vec.to_s
# "[42]"
p vec[0]
# 42

The foreign objects passed to R are implicitly treated as specific R types. The following table gives some examples:

Example of foreign object (Java) Viewed ‘as if’ on the R side
int[] {1,2,3} c(1L,2L,3L)
int[][] { {1, 2, 3}, {1, 2, 3} } matrix(c(1:3,1:3),nrow=3)
int[][] { {1, 2, 3}, {1, 3} } not supported: raises error
Object[] {1, ‘a’, ‘1’} list(1L, ‘a’, ‘1’)
42 42L

In the following example, we can simply pass the Ruby array to the R built-in function sum, which will work with the Ruby array as if it was an integer vector.

sum(eval.polyglot('ruby', '[1,2,3]'))

Foreign objects can be also explicitly wrapped into adapters that make them look like the desired R type. In such a case, no data copying occurs, if possible. The code snippet below shows the most common use cases:

# gives list instead of an integer vector
as.list(eval.polyglot('ruby', '[1,2,3]'))

# assume the following Java code:
# public class ClassWithArrays {
#   public boolean[] b = {true, false, true};
#   public int[] i = {1, 2, 3};
# }

x <- new('ClassWithArrays'); # see Java interop below
as.list(x)

# gives: list(c(T,F,T), c(1L,2L,3L))

For more details, refer to the executable specification of the implicit and explicit foreign objects conversions.

Note: R contexts started from other languages, or Java (as opposed to via the R script), will default to non interactive mode, similar to Rscript. This has implications on console output (the results are not echoed) and graphics (the output defaults to a file instead of a window), and some packages may behave differently in non-interactive mode.

Bellow is a list of available R interoperability builtin functions. For more information see the R --help message and try these examples:

> help(java.type)
> ?java.type
> example(java.type)

See the Polyglot Programming reference for more information about interoperability with other programming languages.