Skip to content

on.exit() & sys.on.exit(): Calling them via eval() does not work as hoped

3 messages · Peter Meilstrup, Henrik Bengtsson

#
Why does the following eval() call on sys.on.exit() not return what I
expect/evaluate in the proper environment?

foo <- function() {
  cat("foo()...\n");
  on.exit( message("exiting") )

  cat("sys.on.exit():\n")
  res <- sys.on.exit()
  print(res)

  cat("eval(sys.on.exit()):\n")
  expr <- quote(sys.on.exit())
  print(expr)
  res <- eval(expr)
  print(res)

  cat("foo()...done\n")
}
foo()...
sys.on.exit():
message("exiting")
eval(sys.on.exit()):
sys.on.exit()
NULL
foo()...done
exiting

Similar problems appear when I try to "record" on.exit() expressions
via eval().  It appears that the "primitives" on.exit() and
sys.on.exit() do something rather special.  Is there a solution to
what I'm trying to do?

The reason why I'm doing this in the first place, is that I'm trying
to implement onExit(<expr>, where="replace"), onExit(<expr>,
where="last"), and onExit(<expr>, where="first").

Thanks,

Henrik
#
eval() tends to be able to convince normal functions of where they are
executing, but primitive functions use different methods to get their
evaluation context and aren't as easily fooled. It turns out do.call()
works better on primitive functions, and it will work for "on.exit".
However I wasn't able to get 'sys.on.exit' to work.

add_on_exit <- function(what) {
  do.call("on.exit", list(substitute(what), add=TRUE), envir=parent.frame())
}

bar <- function() {
  on.exit(print("exit 1"))
  eval(quote(on.exit(print("exit 2"), add=TRUE))) #nope
  do.call("on.exit", alist(print("exit 3"), add=TRUE))
  add_on_exit(print("exit 4"))
  cat("sys.on.exit():\n")
  x <- sys.on.exit()
  print(x)
  cat("----- exiting\n")
}
[1] "exit 2"
sys.on.exit():
{
    print("exit 1")
    print("exit 3")
    print("exit 4")
}
----- exiting
[1] "exit 1"
[1] "exit 3"
[1] "exit 4"
On Sat, Nov 2, 2013 at 9:24 PM, Henrik Bengtsson <hb at biostat.ucsf.edu> wrote:
#
On Sun, Nov 3, 2013 at 2:16 AM, Peter Meilstrup
<peter.meilstrup at gmail.com> wrote:
Brilliant wording :)
Interesting, but also worrying at the same time.  Since these are
undocumented(*) "features" of on.exit()/sys.on.exit() and it works for
on.exit() and not sys.on.exit(), it also means that I'm not sure if I
can rely on this do.call() workaround to not break in the future.  If
would be great to hear what the R core team thinks about this.

(*) There is a small note in help("on.exit") saying "This is a
?special? primitive function: it only evaluates the argument add.".

/Henrik