8

What I'm trying to do

Write a tryCatch that will handle an error value but will ignore a warning. As an example

foo <- function(x) {
  if (x == 1) {
    warning('Warning')
  } else if (x == 0) {
    stop('Error')
  }
  return(1)
}

bar <- function(x){
  tryCatch(
    expr    = foo(x),
    error   = identity,
    warning = function(w) invokeRestart("muffleWarning")
  )
}

So foo warns you if you pass a 0, and errors if you pass a 1. The intent of bar is that you get an error if you pass a 0, but it suppresses the warning generated by bar if you pass a 1. The invokeRestart("muffleWarning") command comes from the definition of suppressWarnings. It does not work in the construction I have here and I do not know why. (Ironically it generates an error, so trying that successfully escalated a warning I didn't want into an error that I can't interpret.)

The Dumb Answer (TM) I don't want to use and why

This definition of bar will work

bar <- function(x){
  tryCatch(
    expr    = foo(x),
    error   = SomeFunctionThatDoesNotMatter,
    warning = function(w){suppressWarnings(foo(x))}
  )
}

bar does exactly what I want it to, but it does it in a potentially terrible way. Imagine that instead of expr = foo(x) as I have here, that I have expr = lapply(X=1:50, ...) and that the FUN takes an hour to run. If X[50] generates the only warning then my run time has double from 50 hours to 100 hours (yuck).

The Questions

  1. Why does invokeRestart("muffleWarning") not work in my example above?
  2. When using tryCatch, what function should be assigned to warning in order to allow the code to simply keep running and suppress the warnings that are generated?

Thanks for reading!

Adam Hoelscher
  • 1,804
  • 2
  • 17
  • 33
  • 1
    Try `warning = function(w) { }` – nrussell Mar 03 '16 at 23:36
  • I need `bar` to still return the value of `foo(x)` – Adam Hoelscher Mar 03 '16 at 23:43
  • 4
    Use `withCallingHandlers()`, illustrated [here](http://stackoverflow.com/questions/4948361/how-do-i-save-warnings-and-errors-as-output-from-a-function/4952908#4952908) – Martin Morgan Mar 04 '16 at 02:56
  • @MartinMorgan: that works. There seems to be a little overhead (which is almost certainly unavoidable). Do you want to "answer" the question? Also, any idea why `invokeRestart("muffleWarning")` works inside `withCallingHandlers()`, but not inside `tryCatch`? – Adam Hoelscher Mar 05 '16 at 00:20
  • 3
    The answer to use `withCallingHandlers()` has been given before, so no value 'answering' again. See ?withCallingHandlers for the difference with tryCatch. The former remembers the call stack down to the point where the condition was signaled, so execution can resume where it left off. tryCatch unwinds the call stack to the point where tryCatch was established, so execution can't resume. You can use an error handler with withCallingHandlers, or a warning handler with tryCatch, but neither use makes sense: an error means that the code can't continue, and a warning doesn't mean you have to stop. – Martin Morgan Mar 05 '16 at 01:30

1 Answers1

2

I ran into this problem after following nrussell's intuition. The solution is to replace the generic

tryCatch({
  some_fn()
}, warning = function(w) {
  print(paste('warning:', w))
}, error = function(e) {
  print(paste('error:', e))
})

with

tryCatch({
  some_fn()
}, error = function(e) {
  print(paste('error:', e))
})

This format/syntax has worked for me. You could easily enclose it in a function like you need to

3pitt
  • 899
  • 13
  • 21