# ------------ Environment example ------------
file_exists <- TRUE
clear_files <- function(e){
print('Clean some shared files')
# do something to remove files
file_exists <<- FALSE
}
# e1, e2 both require file existence
e1 <- new.env()
e1$valid <- function(){ file_exists }
e2 <- new.env()
e2$valid <- function(){ file_exists }
e1$valid(); e2$valid()
# we don't want to remove files when either e1,e2 gets
# garbage collected, however, we want to run `clear_files`
# when system garbage collecting *both* e1 and e2
# Make sure `key`s are identical
shared_finalizer(e1, 'cleanXXXfiles', clear_files)
shared_finalizer(e2, 'cleanXXXfiles', clear_files)
# Now remove e1, files are not cleaned, and e2 is still valid
rm(e1); invisible(gc(verbose = FALSE))
e2$valid() # TRUE
file_exists # TRUE
# remove both e1 and e2, and file gets removed
rm(e2); invisible(gc(verbose = FALSE))
file_exists # FALSE
# ------------ R6 example ------------
cls <- R6::R6Class(
classname = '...demo...',
cloneable = TRUE,
private = list(
finalize = function(){
cat('Finalize private resource\n')
}
),
public = list(
file_path = character(0),
shared_finalize = function(){
cat('Finalize shared resource - ', self$file_path, '\n')
},
initialize = function(file_path){
self$file_path = file_path
shared_finalizer(self, key = self$file_path)
}
)
)
e1 <- cls$new('file1')
rm(e1); invisible(gc(verbose = FALSE))
e1 <- cls$new('file2')
# A copy of e1
e2 <- e1$clone()
# unfortunately, we have to manually register
shared_finalizer(e2, key = e2$file_path)
# Remove e1, gc only free private resource
rm(e1); invisible(gc(verbose = FALSE))
# remove e1 and e2, run shared finalize
rm(e2); invisible(gc(verbose = FALSE))
# ------------ fastmap/fastmap2 example -----------
# No formals needed for fastmap/fastmap2
fin <- function(){
cat('Finalizer is called\n')
}
# single reference case
e1 <- dipsaus::fastmap2()
shared_finalizer(e1, 'fin-fastmap2', fin = fin)
invisible(gc(verbose = FALSE)) # Not triggered
rm(e1); invisible(gc(verbose = FALSE)) # triggered
# multiple reference case
e1 <- dipsaus::fastmap2()
e2 <- dipsaus::fastmap2()
shared_finalizer(e1, 'fin-fastmap2', fin = fin)
shared_finalizer(e2, 'fin-fastmap2', fin = fin)
rm(e1); invisible(gc(verbose = FALSE)) # Not triggered
rm(e2); invisible(gc(verbose = FALSE)) # triggered
# ------------ Native reg.finalizer fails example ------------
# This example shows a failure case using base::reg.finalizer
file_exists <- TRUE
clear_files <- function(e){
print('Clean some shared files')
# do something to remove files
file_exists <<- FALSE
}
# e1, e2 both require file existence
e1 <- new.env()
e1$valid <- function(){ file_exists }
e2 <- new.env()
e2$valid <- function(){ file_exists }
reg.finalizer(e1, clear_files)
reg.finalizer(e2, clear_files)
gc()
file_exists
# removing e1 will invalidate e2
rm(e1); gc()
e2$valid() # FALSE
# Clean-ups
rm(e2); gc()
Run the code above in your browser using DataLab