Unable to access object inside function using an external function R6 - r

I have a R6 class with code like this
# Cutting out lots of code and only putting in relevant lines
public(
function1 <- function(){
var <- xyz$abc
},
function2 <- function(){
xyz <- blah blah
z <- function1()
}
)
When calling function2 I get an error in function1 saying that xyz is not found even though its assigned in function2 which is called before function1
Please let me know if I am understanding this correctly and how to fix it.

For "traditional" R functions the parent of the evaluation environment of a function is the calling environment.
For R6 function this not the same. The parent of the evaluation environment of a method is an environment enclosing the self variable that gives access to object properties.
You can test this by adding
print(ls(parent.env(environment()))) in your method.
This means that you can't have access to your xyz variable in function1. You must use public or private variables or pass it as a parameter to your function.
By the way you must also prepend self$ to the call of function1 (self$function1())

Related

Idiom for default S4 method?

Is there any agreed upon way of writing a fallback method for an S4 generic? I mean, if no signatures are matched, do you write a function to be used as default method that throws perhaps a message() explaining valid signatures? And what return value do you use? Or do you throw an error? Or do you do nothing at all and let R throw the usual error "unable to find an inherited method for function (...)".
Any recommendation?
Yes, there’s a agreed-on way, depending on whether a good default function already exists as a non-generic or not.
1. If there’s already a non-generic function that can serve as a default
Simply make it generic:
setGeneric('function_name')
2. If there’s no non-generic default function yet
Define a new generic
setGeneric(
'function_name',
function (object) {
standardGeneric('function_name')
}
)
Add a default implementation with catch-all parameters
setMethod(
'function_name',
signature(object = 'ANY'),
function (object) {
…
}
)
If you can write a generic that might plausibly work for a wide variety of possible classes, then it is common to do so. For example, the (S3) default method for terms tries to find a $terms component (or attribute — note that this includes the case when the argument is an S4 object with a #terms slot) in its first argument:
function (x, ...)
{
v <- x$terms
if (is.null(v)) {
v <- attr(x, "terms")
if (is.null(v))
stop("no terms component nor attribute")
}
v
}
(terms happens to be an S3 generic but there is no reason why it would not still behave this way if it were S4.)
If there is no sensible thing you can do then all you can really write for a default method is a function that accepts all the arguments in the signature of the generic (plus ... in case there are some methods that have extra arguments) and just calls stop with an error message along the lines of what you suggest.
In S3, you didn't need to do this — you could just not define the default method. This is the case with predict — if you call predict(2,3) say then you will get an error no applicable method for 'predict' applied to an object of class "c('double', 'numeric')". In S4, you will need to define such a default method yourself in the call to setGeneric.

How to access 'this' in a java method?

I have the following javascript method:
myFunc = function(callback) { callback.call(this, "hello", "world"); }
and I´m passing a java object that implements the 'call' method. In the java call method I get the two parameters "hello" and "world", but not 'this' (of course). Is there a way to access 'this' from java?
I´m interfacing java with d3.js and d3 has lots of callbacks in this way and 'this' is where d3 stores a selection.
Thanks
I´m not actually coding in Java but JRuby. In order to make a Java example
I´ll have to simplify my code bellow. Maybe this can help some. If not,
I´ll try to do a Java example.
# Function f1 will call the callback methods cb1 and cb2 with 'this' variable
# This is just a notation for creating javascript function. It calls
# #browser.executeJavaScriptAndReturnValue(scrpt), whith the function
# body (everything between EOT) modified to make a valid javascript script.
# f1 is a function with 2 arguments cb1, and cb2 which should be the
# callback functions
f1 = B.function(<<-EOT)
(cb1, cb2) {
cb1.call(this, "banana", "milk");
cb2.call(this, "arroz", "feijao");
}
EOT
# Proc is a closure. It receives two arguments |food1, food2|. This will
# become a java object per JRuby´s magic
proc = Proc.new { |food1, food2| puts "I hate #{food1} and #{food2}" }
# now call method f1 passing proc as the first argument and the block as
# the second argument. So cb1 = proc and cb2 = <the block bellow>. Method
# 'send' grabs the given arguments, converts them to java objects and then
# calls jxBrowser 'invoke' method with the given arguments.
f1.send(proc) { |food1, food2| puts "eu gosto de #{food1} e #{food2}" }
The result of executing this code is:
I hate banana and milk
eu gosto de arroz e feijao
As can be seen, the 'this' variable is just gone... I would like to be able to
capture the 'this' variable somehow in order to be able to use the context in the blocks. I´ve managed to make a workaround that allows capturing the 'this' variable, but it requires wrapping the block in another javascript function.
The whole idea of this code is to allow a JRuby developer to write Ruby code and get this code executed in jxBrowser without needing to use any javascript. Examples of this can already be seen by downloading mdarray-sol GEM, or going to https://github.com/rbotafogo/mdarray-sol. There you can see multiple examples of using d3.js with JRuby.
Please make sure that you follow the instruction at https://jxbrowser.support.teamdev.com/support/solutions/articles/9000013062-calling-java-from-javascript and inject your Java object with the call() method correctly:
Java code:
browser.addScriptContextListener(new ScriptContextAdapter() {
#Override
public void onScriptContextCreated(ScriptContextEvent event) {
Browser browser = event.getBrowser();
JSValue window = browser.executeJavaScriptAndReturnValue("window");
window.asObject().setProperty("java", new JavaObject());
}
});
...
public static class JavaObject {
public void call(JSValue window, String message) {
System.out.println(message);
}
}
JavaScript code:
window.java.call(window, 'Hello Java!');

How to export new generic function for new S3 class?

I define a new function work_with_myS3 that is supposed to work with my new S3 class myS3:
work_with_myS3 = function (x) {
UseMethod("work_with_myS3", x)
}
work_with_myS3.myS3 = function(x) {
some code
}
When I source this in my normal R session (I'm using RStudio), it behaves exactly as expected. When I feed it an myS3 object, it works; when I feed it something strange, it throws an error:
> work_with_myS3(123)
Error in UseMethod("work_with_myS3", x) :
no applicable method for 'work_with_myS3' applied to an object of class "c('double', 'numeric')"
However, when I include this in my package, build it, reload it and try to call it:
Error: could not find function "work_with_myS3"
Help page works fine though, calling ?work_with_myS3. This is how I document it by devtools::document():
#' Do stuff with myS3
#'
#' What it does
#' #import dplyr
#' #param x object of class myS3
#' #method work_with_myS3 myS3
#' #export
There is also an entry in the namespace:
S3method(work_with_myS3,myS3)
Why is this, and how to make the function available in the package? I suspect I'm making some trivial mistake.
When you call work_with_myS3 with an object of class myS3 the UseMethod function looks for:
work_with_myS3.myS3 or
work_with_myS3.default
Therefore you need to export work_with_myS3.myS3, so
#' #export
work_with_myS3.myS3 = function(x) {
## do stuff
}
Alternatively, you could define a default method and export that.

Proper way to implement S3 dispatch on R6 classes

I have an R6 class and I want to add an S3 method for it. The documentation I found mentioned briefly that in order to use S3 dispatch on R6 you must have class = TRUE, but I couldn't find an example of how it should be done.
I did see empirically that simply writing an S3 method in the form s3generic.r6class worked, but I wanted to know if that is indeed to right way to write an S3 method for R6.
For example, say I have an R6 class that enhances a list
library(R6)
R6list <- R6Class(
"R6list",
public = list(
orig = NULL,
initialize = function(x) {
self$orig <- x
}
)
)
Question 1
Naturally, I want to provide a method for obtaining the underlying list, so I wanted to add an as.list method. Is it standard to add both an S3 generic AND a as.list public function inside the class? My intuitive answer is to add both.
R6list <- R6Class(
"R6list",
public = list(
orig = NULL,
initialize = function(x) {
self$orig <- x
},
as.list = function() {
self$orig
}
)
)
as.list.R6list <- function(x, ...) {
x$as.list()
}
So that now if I have an object mylist <- R6list$new(as.list(letters[1:5])) I can either call as.list(mylist) or mylist$as.list(). Is one of those preferred over the other?
Question 2
Is there anything special about writing an S3 method for R6 classes, or is what I wrote above sufficient and the correct way? I wasn't sure if the S3 method has to be written outside of the class definition, or if R6 somehow provides a way to write S3 methods within it so that all the code relating to the class is localized.
I asked Winston Chang, the author of R6, about this on Github. According to him, the code provided in Question 1 above is the correct way of writing S3 methods for R6 classes.

Call method in other package by name?

I'm trying to call a method in another package by the name of the method (using the reflect package) but I'm not sure exactly how to do it.
What I'm trying so far is,
reflect.ValueOf(controller).MethodByName(action_name).Call()
(where controller is the other package)
Any ideas?
You can't do this using pkg/reflect. For this to work, packages would need to be first class citizens, which they are not.
Your best bet is to store the functions you want to access in a map[string]interface{} and look up
the function in the map:
func Foo() { println("foo?") }
m := map[string]interface{}{
"foo": Foo
}
f := m["foo"].(func())
f()

Resources