r-lib / R6

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

Finalize method for cloned objects is executed in the wrong environment #167

Closed s-fleck closed 5 years ago

s-fleck commented 5 years ago

When cloning an R6 object, it seems the finalize method still refers to the wrong Object. The code below should illustrate the problem quite well:

happy <- R6::R6Class(
  public = list(
    foo = NULL,
    initialize = function() {self$foo <- ":("},
    happyify   = function() {self$foo <- ":)"},
    finalize   = function() {cat("foo: ", self$foo, "\n")}
  )
)

x <- happy$new()
y <- x$clone()

y$happyify()
y$.__enclos_env__$self$foo

#> [1] ":)"

rm(y)
gc()

#> foo:  :( 

This could be related to #155 but I tried it with the newest dev version from github, and the problem still persisted :(

workarounds would also be welcome.

wch commented 5 years ago

It looks like y's finalizer actually isn't being run at all. The foo :( you're seeing is from something else -- I think it's probably left over from previous runs. You can see this better if you start off by clearing everything, or in a new R session:

# Start off by removing everything
rm(list = ls(all.names = TRUE))
gc()

happy <- R6::R6Class(
  public = list(
    foo = NULL,
    initialize = function() {self$foo <- ":("},
    happyify   = function() {self$foo <- ":)"},
    finalize   = function() {cat("foo: ", self$foo, "\n")}
  )
)
x <- happy$new()
y <- x$clone()
y$happyify()
rm(y)
gc()

rm(x)
gc()
#>  foo:  :(

The reason that y's finalizer isn't being run is because the clone method currently doesn't register the finalizer, whereas the new method does:

https://github.com/r-lib/R6/blob/748bb602b42825bdef8b970ab37f62bf83454a83/R/new.R#L151-L168

wch commented 5 years ago

Fixed by #180.