oracle / fastr

A high-performance implementation of the R programming language, built on GraalVM.
Other
626 stars 64 forks source link

Unexpected behaviour Scala Tuple2 vs Tuple3 to Polyglot #62

Closed NRBPerdijk closed 5 years ago

NRBPerdijk commented 5 years ago

Edit: this problem occurs in RC13 and RC14, older versions have not been tested.

Hello!

We ran into unexpected behaviour on the Scala/FastR interface via GraalVM when transferring tuple objects.

Given the following R code:

firstR <- function(scalaTuple) {
    print(scalaTuple$_1)
    print(scalaTuple$_2)
    scalaTuple$_1
}

When the above is assigned to rFunc this will work from Scala: rFunc(("First, "Call"))

it will print:

[1] "First"
[1] "Call"

This won't work from Scala: rFunc(("First", "Call", "!"))

it will print:

[polyglot value]
named list()
[polyglot value]
named list()

I've created a small repository that you can checkout to reproduce the issue. fastRBug

It doesn't really seem to matter what kind of values are part of the Tuple (String, Int, etc...): If you give it a Tuple of 2 elements, it will work as expected, but it will break when you add a third...

steve-s commented 5 years ago

Hello Nathan,

thank you for another detailed report with source code for reproduction.

The interop with JVM languages uses standard Java reflection to find out what public fields and methods are available on a given object. In the case of Tuple2, it looks like it has two public fields _1 and _2 whereas Tuple3 has no public fields but public methods _1, _2, and _3. So when you access Tuple3 like this: scalaTuple$_1 what you're getting is a method, not the value. You should be actually able to call that method and get the value.

To have a generic solution, you may consider wrapping the tuples in ProxyObject before passing them to FastR.

NRBPerdijk commented 5 years ago

Thanks for the reply!

That's... interesting... The Scala doc handles Tuple2 and Tuple3 the same: their elements are val (fields), not def (methods). Somehow Java reflection indeed turns up something different: approaching the Tuple3 values as a function returns the value they store.

I think that from now on we'll use the ProxyObject interface, to avoid further surprises. 😄 👍

steve-s commented 5 years ago

The Scala doc handles Tuple2 and Tuple3 the same: their elements are val (fields), not def (methods). Somehow Java reflection indeed turns up something different: approaching the Tuple3 values as a function returns the value they store.

yes, I was looking at their source code in Scala standard library and it didn't seem to me that they should be any different (but I am not scala expert) so I was puzzled and had to debug all the way down to the Truffle framework level to see that reflection really gives different metadata for the two.

Note: seems answered to me now, so I am closing.

steve-s commented 5 years ago

This may be also of interest: https://github.com/graalvm/graaljs/issues/94#issuecomment-476841280

NRBPerdijk commented 5 years ago

That is indeed interesting, I'll be watching that development.