Suppose that there is a finicky function f()
that is costly to evaluate. It may be an optimisation algorithm that can throw a warning if it terminated without an error but failed some checks (e.g. max. iterations reached). I want to save the output of f()
and the warnings if there were any because these warnings contain valuable information.
These solutions rely either on calling the function for the second time or on using withCallingHandlers
. Frankly, there is so little documentation or examples online for withCallingHandlers
, I cannot understand what this function does by looking at the definition.
The solution purrr::capture_output()
relies on creating a temporary file and then, reading the lines from it. The problem is, I am trying to catch the warnings from millions of calls (small optimisation problems at the inner look of the function, and it is called millions, if not billions of times), so creating of a file()
every time could be precarious (these functions are called in parallel).
Here is a MWE: there is a slow function (1 second) that may or may not throw a warning, and capturing the warning requires a second evaluation (the code below produces 2 warnings and 2 warning-free results = 2 + 2*2 = 6 seconds):
f <- function(i) {
Sys.sleep(1)
if (i < 3) warning(paste0("i is too small, took ", sample(3:10, 1),
" iterations, code ", sample(2:5, 1), "."))
return(i)
}
set.seed(1)
f(1) # Warning
f(6) # No warning
saveWarnSlow <- function(i) {
tryCatch(f(i), warning = function(w) list(output = f(i), warning = w))
}
system.time(out <- lapply(1:4, saveWarnSlow)) # Runs for 6 seconds
sapply(out, function(x) if (length(x) == 1) "OK" else as.character(x$warning))
# [1] "simpleWarning in f(i): i is too small, took 9 iterations, code 2.\n"
# [2] "simpleWarning in f(i): i is too small, took 9 iterations, code 4.\n"
# [3] "OK"
# [4] "OK"
Maybe this is due to my poor knowledge on condition handling and recovery, but... how does on get rid of the repeated function evaluation to save the warning?