Search code examples
rfinalizerr-package

reg.finalizer() in an R package does not execute at the end of an R session


From the documentation ?reg.finalizer in R:

Inter alia, it provides a way to program code to be run at the end of an R session without manipulating .Last. For use in a package, it is often a good idea to set a finalizer on an object in the namespace: then it will be called at the end of the session, or soon after the namespace is unloaded if that is done during the session.

It seems that I can use reg.finalizer() to run certain code when an R session is ended, but it does not work for me. I have prepared a minimal package at https://github.com/yihui/finalizer-test, which basically contains the code below:

e = new.env()

reg.finalizer(e, function(e) {
  message('Bye!')
}, onexit = TRUE)

If I simply run the above code in an interactive R session and quit the session, I can see the message Bye!, but if I install the above package (you can use devtools::install_github('yihui/finalizer-test')), load it in an R session, and quit the R session, I don't see the message. I wonder why the finalizer is not executed in this case.

FWIW, when I install the package, I can see the message Bye!:

$ R CMD INSTALL .

* installing to library ‘/Users/yihui/R’
* installing *source* package ‘finalizer’ ...
** R
** preparing package for lazy loading
No man pages found in package  ‘finalizer’ 
** help
*** installing help indices
Bye!
** building package indices
** testing if installed package can be loaded
* DONE (finalizer)

I don't see the message, either, when I run the command below:

$ R -e "library(finalizer)"
> library(finalizer)
> 
> 
$ 

Solution

  • It works if you register the finalizer function to the package name space environment. You can use the .onLoad hook for that:

    e = new.env()
    
    reg.finalizer(e, function(e) {
      message('Object Bye!')
    }, onexit = TRUE)
    
    
    finalize <- function(env) {
       print(ls(env))
       message("Bye from Name space Finalizer")
    }
    
    
    .onLoad <- function(libname, pkgname) {
       parent <- parent.env(environment())
       print(str(parent))
       reg.finalizer(parent, finalize, onexit= TRUE)
    }
    

    The object finalizer function is not called but since you have the whole namespace environment you probably don't need it.

    I created a fork of your test package on https://github.com/mpbastos/finalizer-test:

    > devtools::install_git("https://github.com/mpbastos/finalizer-test")
    Downloading git repo https://github.com/mpbastos/finalizer-test
    Installing finalizer
    "C:/PROGRA~1/R/R-34~1.0/bin/x64/R" --no-site-file --no-environ --no-save  \
      --no-restore --quiet CMD INSTALL  \
      "C:/Users/mbastos/AppData/Local/Temp/RtmpOGymjQ/file5cf829e63957"  \
      --library="\\sharedfs/MyDocs6/mbastos/Documents/R/win-library/3.4"  \
      --install-tests
    
    * installing *source* package 'finalizer' ...
    ** R
    ** preparing package for lazy loading
    ** help
    No man pages found in package  'finalizer'
    *** installing help indices
    ** building package indices
    Object Bye!
    ** testing if installed package can be loaded
    *** arch - i386
    <environment: namespace:finalizer>
    NULL
    [1] "e"        "finalize"
    Bye from Name space Finalizer
    *** arch - x64
    <environment: namespace:finalizer>
    NULL
    [1] "e"        "finalize"
    Bye from Name space Finalizer
    * DONE (finalizer)
    > library(finalizer)
    <environment: namespace:finalizer>
    NULL
    > q()
    Save workspace image? [y/n/c]: n
    [1] "e"        "finalize"
    Bye from Name space Finalizer