updating method definitions in R6 object instance

纵饮孤独 提交于 2019-12-23 16:53:23

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!