What exactly happens in
tryCatch(warning("W"),warning = function(c) cat(c$message))
As far as I understand this the call warning("W")
creates a condition object c
of type warning
and then someone (who?) looks for a handler (where? and recognizes the handler how?) and calls the handler on c
.
The task of tryCatch
is only to "establish" the handlers. What does this mean? In short the question is: how exactly does the condition object get to its handler?
In my experience, tryCatch
is used to catch and either ignore or specifically handle errors and warnings. While you can do warnings
with this function, I see it more often used with withCallingHandlers
(and invokeRestart("muffleWarning")
).
The Advanced R book is a good reference for many topics; for this, I'd recommend two chapters:
Exceptions and debugging, where Hadley highlights one key difference:
withCallingHandlers()
is a variant oftryCatch()
that establishes local handlers, whereastryCatch()
registers exiting handlers. Local handlers are called in the same context as where the condition is signalled, without interrupting the execution of the function. When a exiting handler fromtryCatch()
is called, the execution of the function is interrupted and the handler is called.withCallingHandlers()
is rarely needed, but is useful to be aware of.
Bold emphasis is mine, to highlight that tryCatch
interrupts, withCallingHandlers
does not. This means that when a warning is raised, nothing else is executed:
tryCatch({warning("foo");message("bar");}, warning=function(w) conditionMessage(w))
# [1] "foo"
tryCatch({warning("foo");message("bar");})
# Warning in tryCatchList(expr, classes, parentenv, handlers) : foo
# bar
Further details/examples are in the Beyond exception handling chapter.
tryCatch
executes the expression in a context where anything "raised" is optionally caught and potentially altered, ignored, logged, etc. A common method I see is to accept any error and return a known entity (now without an error), such as
ret <- tryCatch(
something_that_fails(),
error = function(e) FALSE)
Unlike other operating systems that allow precise filters on what to handle (e.g., python and its try: ... except ValueError:
syntax, ref: https://docs.python.org/3/tutorial/errors.html#handling-exceptions), R is a bit coarser in that it catches all errors you can get to figure out what kind of error it is.
If you look at the source of tryCatch
and trace around its use of its self-defined functions, you'll see that ultimately it calls an R function .addCondHands
that includes the list of handlers, matching on the names of the handlers (typically error
and warning
, though perhaps others might be used?). (The source for that function can be found here, though I don't find it very helpful in this context).
I don't know exactly how to answer "how exactly ... get to its handler", other than an exception is thrown, it is caught, and the handler is executed with the error object as an argument.