问题
How can I update the method definition of an R6 class instance?
S3 uses the current method defintion, as I would expect. With R5 (Reference Classes) I can use myInstance=myInstance$copy(). With R6 I tried myInstance = myInstance$clone() but myInstance$someMethod() still invokes the old code.
I need this, when I load object instances from a dump created on a long-running process. I want to debug and change the code on an object state after a long-running computation. Therefore, I cannot just create a new instance and rerun the initialization. Even better than the R5 copy method (which does not update references to the instance), would be a method that assigs the currently defined behaviour (i.e methods definitions) of the class and all super classes to the instance.
Here is an example:
library(R6)
Person <- R6Class("Person",
lock_objects=FALSE,
public = list(
name = NULL,
initialize = function(name = NA, hair = NA) {
self$name <- name
self$greet()
},
greet = function() {
cat(paste0("Hello, my name is ", self$name, ".\n"))
}
)
)
# create an instance
thomas <- Person$new("Thomas","brown")
# modify the behaviour of Person
Person <- R6Class("Person",
lock_objects=FALSE,
public = list(
name = NULL,
initialize = function(name = NA, hair = NA) {
self$name <- name
self$greet()
},
greet = function() {
cat(paste0("Modified greet from ", self$name, ".\n"))
}
)
)
t1 <- Person$new("t1") # greet function updated
t2 <- thomas$clone()
t2$greet() # greet function not updated in thomas nor t2
回答1:
There is a simple workaround for this problem. Set the default value of the class method to NULL
and update this value within the initialize()
method. Now, you can change the method as you like without receiving this error. For example:
aClass <- R6::R6Class("className",
public = list(
f = NULL,
initialize = function(...) {
self$f = sum
},
update_f = function(x) {
self$f = x
}
)
)
test <- aClass$new()
test$f
test$update_f(mean)
test$f
Or, one can modify the function in-place:
test$f <- median
test$f
That should resolve the issue. I also posted this answer here.
回答2:
I came up with the following hack.
Continuing from the code in the question, I managed to change the method definition of greet
in R6 object instance thomas
:
replacePublicR6Method <- function( r6Instance, fName, fun){
selfEnv <- environment(r6Instance[[fName]])$self
properEnv <- environment( r6Instance[[fName]] )
unlockBinding(fName, selfEnv)
selfEnv[[fName]] <- fun
environment(selfEnv[[fName]]) <- properEnv
lockBinding(fName, selfEnv)
}
replacePublicR6Method( thomas, "greet", function(){
cat(paste0("Modified greetings from ", self$name, ".\n"))
})
thomas$greet()
I guess the binding is locked on purpose, and this hack is dirty. Question to the R-wizards: Can this hack break some other behaviour of R6 classes? Will it continue to work with future version of R6 classes?
For experimenting with some code modifications at an object state after a long-running computation this should be ok. So far, it also works on instances of child classes.
来源:https://stackoverflow.com/questions/39914775/updating-method-definitions-in-r6-object-instance