Search code examples
roopr6

Is there any way to remove an R6 object using it's own method?


Taking an example of a basic R6 class given below:

library(R6)

Demo = R6Class("Demo",
           public = list(
             initialize = function(){
               message("demo object initialized!")
             },
             delete = function(){
               #should contain the logic to delete the object
               gc()
             },
             finalize = function(){
               message("demo object deleted!")
             } 
           ))

demoObj = Demo$new()
demoObj$delete()

What should be the logic inside the delete function? Is it possible to delete the object (self)?


Solution

  • I'm not aware of any straightforward way of getting an object in R to "self-destruct" in this way. The object belongs to the environment in which it was created, and there are good reasons for leaving control over the lifetime of an object to the environment in which it was created, rather than to the object itself.

    This doesn't mean there is no way to do it, but effectively you would have to allow the object to look up its own name in its parent frame (using a flag that identifies it only once the deletion process is set in motion), then calling rm on that name in the parent frame. So something like this reprex:

    library(R6)
    
    Demo = R6Class("Demo",
               public = list(
                 initialize = function(){
                   message("demo object initialized!")
                 },
                 delete_flag = FALSE,
                 delete = function(){
                   self$delete_flag <- TRUE
                   pf <- parent.frame()
                   demos <- sapply(ls(pf), function(i) {
                              class(get(i, envir = pf))[1] == "Demo"
                            })
                   this <- ls(pf)[demos][sapply(mget(ls(pf)[demos], envir = pf),
                          function(x) x$delete_flag)]
                   rm(list = this, envir = pf)
                   message("demo object deleted!")
                 }
               ))
    
    demoObj = Demo$new()
    #> demo object initialized!
    
    ls()
    #> [1] "Demo"    "demoObj"
    
    demoObj$delete()
    #> demo object deleted!
    
    ls()
    #> [1] "Demo"
    

    This is designed to ensure that only the correct object is deleted, so for example;

    demoObj1 = Demo$new()
    #> demo object initialized!
    demoObj2 = Demo$new()
    #> demo object initialized!
    demoObj3 = Demo$new()
    #> demo object initialized!
    
    demoObj2$delete()
    #> demo object deleted!
    
    ls()
    #> [1] "Demo"     "demoObj1" "demoObj3"
    

    You can see that only demoObj2 has deleted itself.

    Created on 2020-08-08 by the reprex package (v0.3.0)