A Note on on.exit()

Yihui Xie 2017-05-19

Update on 2020-06-23

The issue mentioned in this post has been fixed in R 4.0.2, thanks to Martin Maechler.

I have used on.exit() for several years, but it was not until the other day that I realized a very weird thing about it: you’d better follow the default positions of its arguments expr and add, i.e., the first argument has to be expr and the second has to be add.

on.exit(expr = NULL, add = FALSE)

If you do on.exit(add = TRUE, {...}), weird things can happen. I discovered this by accident. I have never switched the positions of expr and add before, and I was surprised that R CMD check failed on Travis with an error message that confused me in the beginning:

Error in on.exit(add = TRUE, if (file.exists(main)) { : 
  invalid 'add' argument

I was thinking why add = TRUE was considered invalid. Then I guessed perhaps the expression if (file.exists(main)) {} was treated as the actual value of add. So I switched to the normal order of arguments, and the error was gone.

I tested it a bit more and was totally confused, e.g., why was 1 printed twice below? I guess TRUE was not printed because add was treated as expr.

f = function() {
  on.exit(add = print(TRUE), print(1))
}
f()
# [1] 1
# [1] 1

I don’t have the capability to understand the source code in C, and I’ll leave it experts to explain the weird things I observed. For me, I’ll just never move add before expr again.

BTW, I don’t know the rationale for the default add = FALSE in on.exit(), but I have not used add = FALSE for a single time, so I feel add = TRUE might be a better default. When I want to do something on exit, I almost surely mean do it in addition to the things that I assigned to on.exit() before, instead of cleaning up all previous tasks and only doing this one (add = FALSE).

Update on 2018-01-17

Half a year later, I was bitten by the same problem again in the tinytex package. Never, ever, do on.exit(add = TRUE, expr).