<p>I have used <code>on.exit()</code> 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 <code>expr</code> and <code>add</code>, i.e., the first argument has to be <code>expr</code> and the second has to be <code>add</code>.</p>
<pre><code>on.exit(expr = NULL, add = FALSE)
</code></pre>
<p>If you do <code>on.exit(add = TRUE, {...})</code>, weird things can happen. I discovered this <a href="https://github.com/rstudio/bookdown/commit/1f77a3e4ab">by accident</a>. I have never switched the positions of <code>expr</code> and <code>add</code> before, and I was surprised that <code>R CMD check</code> failed on <a href="https://travis-ci.org/rstudio/bookdown/builds/233076842">Travis</a> with an error message that confused me in the beginning:</p>
<pre><code>Error in on.exit(add = TRUE, if (file.exists(main)) { : 
  invalid 'add' argument
</code></pre>
<p>I was thinking why <code>add = TRUE</code> was considered invalid. Then I guessed perhaps the expression <code>if (file.exists(main)) {}</code> was treated as the actual value of <code>add</code>. So I switched to the normal order of arguments, and the error was gone.</p>
<p>I tested it a bit more and was totally confused, e.g., why was <code>1</code> printed twice below? I guess <code>TRUE</code> was not printed because <code>add</code> was treated as <code>expr</code>.</p>
<pre><code>f = function() {
  on.exit(add = print(TRUE), print(1))
}
f()
# [1] 1
# [1] 1
</code></pre>
<p>I don’t have the capability to understand the <a href="https://github.com/wch/r-source/blob/a7356bf91b/src/main/builtin.c#L131-L186">source code in C</a>, and I’ll leave it experts to explain the weird things I observed. For me, I’ll just never move <code>add</code> before <code>expr</code> again.</p>
<p>BTW, I don’t what the rationale is for the default <code>add = FALSE</code> in <code>on.exit()</code>, but I have not used <code>add = FALSE</code> for a single time, so I feel <code>add = TRUE</code> 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 <code>on.exit()</code> before, instead of cleaning up all previous tasks and only doing this one (<code>add = FALSE</code>).</p>