R ReferenceClass: Call parent method in child object definition - r

I'm trying to implement object-specific method caching in R. I have many different kinds of objects, and many of them implement functions that get called often, take a long time to run, and whose inputs/outputs don't change between executions. So to save time, I want to cache the outputs of these methods to a hash-map, which maps the hash of the parameter inputs to the output. The catch is that these long-running methods reference the object fields, which means that I need the caching to be object-specific. I can't implement a global caching process, because executing the same function on two different instances of the same object typically produces different outputs.
To do this, I've implemented a parent class Cache, which has a hash-map, and implements the 'cache' function. This object can then be inherited by other objects to easily implement object-specific method-caching.
In order to streamline the process, I've also implemented a decorator, so that the methods of the child objects can be easily wrapped in the caching function.
Here's my code:
# Define the infix decorator function
`%decorate%` = function(decorator, f) {
decorator(f)
}
# Cache parent class
Cache =
# ----
setRefClass(
'Cache',
fields =
c(
# PRIVATE: hash map of inputs to outputs
"prev_output_hash_map__"
),
methods =
list(
# Initialize the private values.
initialize =
function(...) {
callSuper(
prev_output_hash_map__ = r2r::hashmap(),
...
)
},
cache =
function(f) {
function(refresh = F,...) {
# Hash the function name and it's inputs
input_hash__ =
rlang::hash(
list(
deparse1(f), # The code of the function
... # The parameter inputs to the function
)
)
# Check to see if the input hash is present in the hash map
# If it isn't execute the inner function and save the results
if(is.null(prev_output_hash_map__[input_hash__][[1]]) | refresh) {
prev_output_hash_map__[[input_hash__]] <<- f(...)
}
# Return the previously saved output
return(prev_output_hash_map__[input_hash__][[1]])
}
}
)
)
# Child class which will implement caching on one or more of its methods
CachingObject =
setRefClass(
"CachingObject",
contains = "Cache",
methods =
list(
# A long-running method that I want to cache the output of
long_running_function =
cache %decorate% function(input1, input2) {
Sys.sleep(10)
return(input1 + input2)
}
)
)
I've verified that the caching logic works correctly outside of the reference class. The problem here is that the 'cache' function is a method of the Cache object, and not defined in the global environment. This means that the method isn't visible when the child object CachingObject is being defined, and I get the following error:
Error in cache %decorate% function(input1, input2) { :
object 'cache' not found
Is there some way to reference the methods of a parent object in the midst of the definition of a child object? If not, is there a way to accomplish what I'm trying to do here?

Related

Unable to access object inside function using an external function R6

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())

How to call Kotlin companion factory method using callBy()?

I have code accepts a class as a parameter and prepares data to call either the constructor for that class of a companion object factory method if the factory method is present.
All works fine when calling the constructor, but I get the error
java.lang.IllegalArgumentException: No argument provided for a required parameter: instance of fun nz.salect.objjson.JVMTest.StudentWithFactory.Companion.fromJson(kotlin.String, kotlin.Int): nz.salect.objjson.JVMTest.StudentWithFactory
when calling the factory method. The factory method in question:
data class StudentWithFactory(val name: String, val years: Int=0) {
companion object {
fun fromJson(name: String="", age: Int = 0):StudentWithFactory {
return StudentWithFactory(name, age)
}
}
}
has no required parameters, unless there is some hidden parameter. Any ideas?
In fact, I reverted removing the parameters completely from fromJson and directly calling the companion method using ::fromJson.callby(emptyMap()). Same error.
It is clear that companion methods need at least one additional parameter. Perhaps the class? Or the companion object?
How can I specify the needed parameter(s)?
The function building up the callBy() is supplied a class (or finds the class from a supplied class) and json names and values.
var funk:KFunction<*>?=null
val companionFuncs=cls.companionObject?.declaredMemberFunctions
if(companionFuncs?.size ?:0 >0){
companionFuncs?.forEach {
if(it.name == "fromJson") funk=it
}
}
val cons:KFunction<T> = if(funk != null)
funk as KFunction<T>
else
cls.primaryConstructor ?: throw IllegalArgumentException("no primary constructor ${cls.simpleName}")
val valuesMap = cons.parameters.filter{it.name in vals}
.associateBy(
{it},
{generateValue(it)}
)
val data = cons.callBy(valuesMap) //as T
return data
In addition to my short answer, a more technical explanation:
Yes, there actually is a hidden parameter and you can see it (for example), if you take a look at the decompiled (to Java) bytecode:
public final class StudentWithFactory {
// ...
public static final class Companion {
// ...
#NotNull
public static StudentWithFactory fromJson$default(StudentWithFactory.Companion var0, String var1, int var2, int var3, Object var4) {
// ...
return var0.fromJson(var1, var2);
}
// ...
}
}
The first parameter (var0) is actually an instance of the companion object. var1 (name) and var2 (age) are the parameters you declared. var3 is a bitmask for determining if explicit values have been passed or if the default ones should be used*. I honestly don't know what var4 is for. It is unused in the Java code. But the imported part is that you only need to worry about var0, var1 and var2 if you want to invoke the function.
So, in the end the non-static version of fromJson* is actually invoked on the instance of the companion object:
var0.fromJson(var1, var2)
*left code out for simplicity
You can use the parameters property to determine how much parameters you have to pass to the function/constructor.
If you call
val paramsConstr = StudentWithFactory::class.primaryConstructor?.parameters
paramsConstr will be of size two as expected, but if you call
val paramsFunc = ::fromJson.parameters
paramsFunc will be of size three. The first element corresponds to the instance of the companion object. So, thats the list of parameters you need to provide.
You can invoke the fromJson like this:
// not using any default parameters
::fromJson.callBy(mapOf(
paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
paramsFunc[1] to "Hello",
paramsFunc[2] to 30
))
// using only the default parameter for "name"
::fromJson.callBy(mapOf(
paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
paramsFunc[2] to 30
))

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!');

Reference class inheritance from external package

I am trying to override a reference class method. Because reference class methods are bound to the class rather than the object, I believe in order to do this I need to define a new reference class which inherits from the old reference class. However the class I am trying to inherit from is defined in an external package to mine (dplyr). I cannot figure out the correct syntax to do this, contains seems to require only a text name, and does not search for class definitions in external packages.
In particular I am trying to inherit from the DbDisconnector reference class from dplyr and override the finalize method.
This correctly finds the parent class, but then cannot assign to it as it is from a different package.
NewDbDisconnector <- setRefClass("NewDbDisconnector",
contains = 'DbDisconnector',
methods = list(
finalize = function() {
message("test")
}
),
where=getNamespace('dplyr')
)
# Error in assign(mname, def, where) (from file.r#75) :
# cannot add bindings to a locked environment
Contains methods only accept strings, they cannot just be given a refClass definition from getRefClass.
NewDbDisconnector <- setRefClass("NewDbDisconnector",
contains = getRefClass("DbDisconnector", getNamespace("dplyr")),
methods = list(
finalize = function() {
message("test")
}
)
)
# Error in FUN(X[[1L]], ...) :
# the 'contains' argument should be the names of superclasses: got an element of class “name”
I would think this should be possible, I just cannot figure out the correct way to do it.
You can import the superclass to your environment:
DbDisconnector <- getFromNamespace("DbDisconnector", "dplyr")
And then set contains = "DbDisconnector" in your class.

Passing param to flex module via url

Im using a few modules repeatedly in a Flex app and varying the conditions by passing in params via the 'loaderInfo.url' var. This works fine for the first iteration of a given module but subsequent attempts will always see the same params as the first creation regardless of what is actually used.
Is there some way to reset this value when the module is created?
private var moduleInfo : IModuleInfo;
private function loadPageModule( pathString : String, pageParam : String ) : void
{
pathString = "modules/" + pathString + ".swf?param=" + pageParam;
moduleInfo = ModuleManager.getModule( pathString );
moduleInfo.addEventListener( ModuleEvent.READY, onPageModuleReady, false, 0, true);
moduleInfo.load( ApplicationDomain.currentDomain, null, null );
}
When I view the param in the 'CreationComplete' handler (eg 'trace( this.loaderInfo.url );') its the same every time (for a given module) regardless of what is actually passed in via the ?param=string. What am I doing wrong?
I'm little confused by your code. "moduleInfo" is a local variable in loadPageModule, meaning after the function executes it should be garbage collected. Typically adding a event listener would stop the object from being GC'ed but you specifically set the "weakListener" argument of addEventListener to true.
Can you set the weakListener argument of addEventListener to false and manually remove the listener in onPageModuleReady? Like below:
// change true to false on this line
moduleInfo.addEventListener( ModuleEvent.READY, onPageModuleReady, false, 0, false);
// tweak onPageModuleReady
private function onPageModuleReady(e:Event):void {
e.target.removeEventListener(ModuleEvent.READY, onPageModuleReady);
// that will allow the object to be GC'ed
...rest of your code
Test it again with that configuration and report back if things change.
Well I don't know why this is doing what its doing.. but.. an effective way to pass unique params to different instances of a module is to use the IModuleInfo.data param. The url method never worked properly (for me).

Resources