Introduction
on.exit()
is a base R function which records expressions to evaluate when
the current function exits.
I was wanting to use on.exit()
in a function that was allocating some resources,
and I explicitly wanted these resources freed in the reverse order.
Working out how to do what I wanted was easy (discussed below), but it lead
me down a path of discovery as I tried to figure out just exactly where and when
the on.exit()
expressions were being executed.
Yesterday I posted some code snippets from this exploration.
This is a follow-up post with some more notes
Capture variable values at time of on.exit()
creation
The following code shows that, by default, values in the on.exit()
expression
are evaluated as the function exits.
f <- function(a, b) {
on.exit(cat("a =", a, " b =", b, "\n"))
a <- a + 1
b <- b + 1
a + b
}
f(1, 2)
## a = 2 b = 3
## [1] 5
However sometimes you might like the on.exit()
expression to capture the
current values of the variables at the time the on.exit()
expression was
captured.
The docs suggest using substitute()
to do this. I’m not sure if the following is
exactly what the docs are suggesting, but this works:
f <- function(a, b) {
eval(substitute(on.exit(cat("a =", a, " b =", b, "\n"))))
a <- a + 1
b <- b + 1
a + b
}
f(1, 2)
## a = 1 b = 2
## [1] 5
Make a function callable only once by removing the function from the calling environment
Antoine Fabri in his {once}
package uses on.exit()
to remove some functions from the calling environment
after they are run for the first (and only!) time.
The following code is a small recreation of this functionality i.e. the function can be called once, and is then removed from the calling environment.
f <- function() {
on.exit(rm('f', envir = parent.frame()))
print("In the function")
}
f()
## [1] "In the function"
f()
## Error in f(): could not find function "f"
on.exit()
in nested functions - abnormal exit with stop()
Nested functions - each with their own on.exit()
- will trigger the evaluation
of the captured exit expressions when a stop()
is called in the innermost
function. The on.exit()
expressions are evaluated from most deeply nested function
out to the initial outer function call.
fa <- function() {on.exit(print("Exit fa()")); stop("Bang!")}
fb <- function() {on.exit(print("Exit fb()")); fa()}
fc <- function() {on.exit(print("Exit fc()")); fb()}
fc()
## Error in fa(): Bang!
## [1] "Exit fa()"
## [1] "Exit fb()"
## [1] "Exit fc()"
on.exit()
in nested functions - abnormal exit with kill
signals.
For those familiar with sending signals to processes, on.exit()
code
may or may not be run when signals are sent.
A common way to send a signal on Unix or MacOS is with the kill
command.
My tests on MacOS with some common signals, show that R only executes the captured on.exit()
expressions
when sent a SIGINT (equivalent to hitting CTRL-C).
Many other signals caused R to terminate completely without the on.exit()
registered expressions
being evaluated.
Other signals had zero noticeable effect.