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.
Related
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?
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
))
I thought classes needed an exportClass directive in NAMESPACE to be exported,
but
Classes defined in a package but not exported are nevertheless exported if there is an initialize method for the class in the code base.
that is to say I can create an instance of the class event though I exported nothing.
so
setClass("example", slots = c( title = "string"))
setClass("example2", slots = c( title = "string"))
and
setMethod("initialize","example, function(.Object, title) {
.Object#title <- title
. Object
})
in the package R directory and NAMESPACE present but with no export directives in it,
results in the possibility to create an instance of the class
library(example_package)
new("example") # ok
new("example2") # fails
I guess this is because initialize is a generics that is already defined
but does it mean you cannot prevent class instantiation by the user of the package if there is an initialize method for the class ?
or maybe put the initialize inside the setClass instruction ?
I have a Kotlin class whose primary (and only) constructor is empty.
I have a reference to this class:
val kClass: KClass<MyClass> = MyClass::class
How do I create an instance of this class using reflection?
In Java I would do myClass.newInstance() but it seems in Kotlin I need to find the constructor first:
kClass.constructors.first().call()
I have seen mention of primaryConstructor in some bug reports but it's not showing up in my IDE.
In your case, Java reflection might be enough: you can use MyClass::class.java and create a new instance in the same way as you would with Java reflection (see #IngoKegel's answer).
But in case there's more than one constructor and you really need to get the primary one (not the default no-arg one), use the primaryConstructor extension function of a KClass<T>. It is a part of Kotlin reflection, which is not shipped within kotlin-stdlib.
To use it, you have to add kotlin-reflect as a dependency, e.g. a in Gradle project:
dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
Assuming that there is ext.kotlin_version, otherwise replace $kotlin_version with the version you use.
Then you will be able to use primaryConstructor, for example:
fun <T : Any> construct(kClass: KClass<T>): T? {
val ctor = kClass.primaryConstructor
return if (ctor != null && ctor.parameters.isEmpty())
ctor.call() else
null
}
You can use the Java class to create new instance:
MyClass::class.java.newInstance()
For those checking this question now, since Kotlin 1.1 there's also createInstance() extension method on KClass
Much like the accepted answer, this function works only in case class has an empty constructor or constructor with all default arguments.
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect.full/create-instance.html
Expanding on Alexeys Answer, to include a primary constructor call with parameters:
/* Example class with no-args constructor */
class MyClass
/* Example class requiring parameters */
class MyClassWithParams(parameter1: String, parameter2: MyClass)
val myKClass: KClass<MyClass> = MyClass::class
val myKClassWithParameters: KClass<MyClassWithParams> = MyClassWithParams::class
/* We can create an object by calling createInstance when no constructor parameters are required as explained in other answers. */
val myObject: MyClass = myKClass.createInstance()
/* To create an object with parameters, we need to get the constructor first, and call it with the parameters instead, similarly to how we would do in Java. */
val myObjectWithParameters: MyClassWithParams? =
myKClassWithParameters.primaryConstructor?.call(
"StringParameter", myObject
)
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.