r-lib / R6

Encapsulated object-oriented programming for R
https://R6.r-lib.org
Other
412 stars 57 forks source link

Issue with `$clone(deep = TRUE)` when private object has a Rcpp class #253

Closed stla closed 1 year ago

stla commented 2 years ago

Hello,

> map1$clone(deep = TRUE)
Error in envRefInferField(x, what, getClass(class(x)), selfEnv) : 
  ‘.__enclos_env__’ is not a valid field or method name for reference class “uMAPR”
> class(map1$.__enclos_env__$private$.map)
[1] "uMAPR"
attr(,"package")
[1] "mapR"
> typeof(map1$.__enclos_env__$private$.map)
[1] "S4"

uMAPR is a class created with Rcpp:

uMAPR <- setRcppClass("uMAPR")

Such an object is an environment:

> is.environment(map1$.__enclos_env__$private$.map)
[1] TRUE
> ls(map1$.__enclos_env__$private$.map)
 [1] "callSuper"        "copy"             "erase"           
 [4] "field"            "getClass"         "getRefClass"     
 [7] "initialize"       "keys"             "merge"           
[10] "ptr"              "show"             "show#envRefClass"
[13] "size"             "usingMethods"     "values"    

But when you $-subset it with an unexisting field:

> map1$.__enclos_env__$private$.map$xxx
Error in envRefInferField(x, what, getClass(class(x)), selfEnv) : 
  ‘xxx’ is not a valid field or method name for reference class “uMAPR”

Thus the error is caused by this piece of code in map1$clone:

      deep_clone <- function(name, value) {
        if (is.environment(value) && !is.null(value$.__enclos_env__)) {
          return(value$clone(deep = TRUE))
        }
        value
      }

There is no error if one replaces !is.null(value$.__enclos_env__) with ".__enclos_env__" %in% ls(value).

cc @eddelbuettel

By the way, there is an external pointer in this object, and the "deep clone" doesn't work: if I modify the deep clone (obtained by the above correction of map1$clone), the modification is also performed on the original object, because of the pointer.

Cheers.