Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setArrayElement does not work on R array/vector #21

Closed
edopalmieri opened this issue Aug 29, 2018 · 4 comments
Closed

setArrayElement does not work on R array/vector #21

edopalmieri opened this issue Aug 29, 2018 · 4 comments

Comments

@edopalmieri
Copy link

edopalmieri commented Aug 29, 2018

Hi,

I am trying to use Value.setArrayElement() to populate a R vector from Java (host side).
I have tried the following:

Value rArray = guestLanguageContext.eval("R", "vector()");
rArray.setArrayElement(0, "somevalue");

While the empty vector is successfully created, calling setArrayElement() like that does not change the content of the R array.

Is it possible to use setArrayElement with an R array? Am I not doing it right or is this an issue with the R implementation?

Thanks
Edoardo.

@steve-s
Copy link
Member

steve-s commented Aug 30, 2018

Hi Edoardo,

R vectors should be immutable so it is questionable how the setArrayElement should behave and we'll need to discuss this internally. However, it is likely that we will change it to throw an exception with a message explaining this.

What you can use to update R vectors are R functions [<- (sets one element) and [[<- (can set more elements). Note that those functions return the new vector and the original stays unchanged. Example (tested on GraalVM RC5 community edition):

Value vec = context.eval("R", "c(1,2,3)");
Value setVecEl = context.eval("R", "`[<-`");
vec = setVecEl.execute(vec, 1, 42);
context.eval("R", "print").execute(vec);

@edopalmieri
Copy link
Author

edopalmieri commented Aug 30, 2018

Hi Steve,

Thanks for the explanation and apologies for my limited knowledge of R vectors.

Indeed, I agree with you on the fact that setArrayElement() should throw with an explanation when trying to use it on an R vector due to its immutability.

Side question: is there a mutable collection in R on which the setElementArray() would work?

Thank you
Edoardo.

@steve-s
Copy link
Member

steve-s commented Aug 31, 2018

apologies for my limited knowledge of R vectors

no need for the apology. We thank you for your feedback! Please feel free to ask more questions and open more issues. We are also looking for a feedback on what features (Java interop, Spark integration, ...) are important for our users (including suggestions on new features!) and what R packages are essential for them. If you could share a bit about your use-case that would be fantastic, but I understand that that is not always possible. You can also reach me at stepan[dot]sindelar-at-oracle.com

You can also check the reference manual for more examples.

Side question: is there a mutable collection in R on which the setElementArray() would work?

the environments have reference semantics in R, but they are more like an object with fields referenced by name. Example:

Value env = context.eval("R", "new.env()");
env.putMember("fieldName", 42);
System.out.println(env.getMember("fieldName"));
context.eval("R", "function (x) print(x$fieldName)").execute(env);

another thing that you can do is to pass arrays from other languages to R. R should be able to handle them in most cases just as if they were vectors. If you come across R builtin functions that cannot handle them, let us know and we'll fix that. The simplest is to just use Java arrays:

context.eval("R", "function(x) sum(x * 2);").execute(new int[] {1, 2, 3}));

you can create a ProxyArray:

context.eval("R", "function(x) sum(x * 2);").execute(ProxyArray.fromArray(1,2,3))

you can create your own implementation of the ProxyArray interface:

private static class MyArray implements ProxyArray {
  @Override
  public Object get(long index) { return index > 10 ? 2 : 1; }

  @Override
  public void set(long index, Value value) { throw new UnsupportedOperationException(); }

  @Override
  public long getSize() { return 100; }
}
// ...
context.eval("R", "function(x) sum(x * 2);").execute(new MyArray())

or you can even use an array from another language like Ruby:

Value rubyArray = context.eval("ruby", "[1,2,3]");
rubyArray.setArrayElement(0, 42);
context.eval("R", "function(x) sum(x * 2);").execute(rubyArray);
// update the Ruby array in R: notice the reference semantics, R does not copy the array.
// Note R has 1-based indexing
context.eval("R", "function(x) { x[[2]] <- 44; }").execute(rubyArray);
assert rubyArray.getArrayElement(1) == 44;   // Java: 0-based indexing

We may reconsider whether it makes sense to apply reference semantics in the last R code snippet:

context.eval("R", "function(x) { x[[2]] <- 44; }")

as it would mean some R code that assumes vectors are immutable may not work with foreign arrays.

I am attaching full example source code.

FastRJavaCmd.zip

@edopalmieri
Copy link
Author

edopalmieri commented Sep 2, 2018

Hi Steve,

Thank you very much for your explanation. Much appreciated.

I am trying to use Graal's Polyglot API to execute scripts written by the users of my platform. My basic requirement is to run JS scripts. However, I am experimenting with R as well because I believe it can bring added value to the system.

My basic requirements for executing these scripts are:

  • sandboxing of the guest code
  • my users developing R scripts should not need to know that their code is running on Graal. This means, for example, that when a variable is passed using top level bindings it should look like a native R type to the guest language developer.

I posted on GraalJS' github a few days ago: oracle/graaljs#45. One of the answers I got in that post suggested to create the guest variable in the host side already in the guest data type in order to meet the second requirement I mentioned above. This works great in JS and Python, and thanks to your advice I managed to make it work in R too (this is why I was trying to use setArrayElement).

In that same post, @lukasstadler mentioned that there is currently a bug on the R side, due to which setting top level bindings with anything other than a native R data type causes the error I posted:
oracle/graaljs#45 (comment)

I will send you an email with a more in depth description of my use case.

Once again thanks for your help.
Edoardo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants