Andreas Kersting
2022-Mar-01 19:05 UTC
[Rd] message(<cond>) and warning(<cond>) circumvent calling handlers and signal the original class, e.g. an error
Hi, There is the same issue with stop():> w <- simpleWarning("careful") > tryCatch(stop(w), condition = identity)<simpleWarning: careful> I very recently stumbled upon this, when a warning was re-raised as an error, which was then not caught by an outer try():> try(+ tryCatch(warning("careful"), warning = function(w) stop(w)), + silent = TRUE + ) Error in doTryCatch(return(expr), name, parentenv, handler) : careful I would also like to see this behavior changed. I think that stop() should always signal an error, warning() a warning and message() a message. Best, Andreas 2022-03-01 19:38 GMT+01:00 "Henrik Bengtsson" <henrik.bengtsson at gmail.com>:> Hi, in help("message", package = "base"), we can read: > > Description: 'message' is used for generating 'simple' diagnostic > messages which are neither warnings nor errors, but nevertheless > represented as conditions. > > From this, I conclude that message() should generate a condition that > are neither warning nor errors. > > However, the following signals a condition of class 'error': > >> e <- simpleError("boom!\n") >> message(e) > boom! > > This can be seen if we do: > >> res <- tryCatch(message(e), condition = identity) >> res > <simpleError: boom! > > This stems from message(e) using signalCondition(e) internally. > > Another problem with this behavior is that message(e) cannot be suppressed: > >> suppressMessages(message(e)) > boom! > > or captured with calling handlers, e.g. > >> res <- withCallingHandlers(message(e), condition = identity) > boom! >> res > NULL > > If we replace e <- simpleError("boom") with e <- > simpleWarning("careful"), we see a similar behavior. These problems > exist also with warning(e). The current behaviors prevent functions > from capturing and relaying message(<error>), message(<warning>), and > warning(<error>). > > I'm happy to post a bug report to <https://bugs.r-project.org/>. > > /Henrik > > PS. BTW, it looks like some recent "..." tweaks to the warning() and > stop() code could be applied also to message(). > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >
iuke-tier@ey m@iii@g oii uiow@@edu
2022-Mar-01 23:12 UTC
[Rd] [External] Re: message(<cond>) and warning(<cond>) circumvent calling handlers and signal the original class, e.g. an error
This is behaving as documented and as intended. If you want to call stop() with a condition argument and you want to have that condition handled as an error then you need to make sure that your condition inherits from "error". One way to do this would be to define something like warningToError <- function(w) errorCondition(conditionMessage(w), warning = w, class = "warningToError") and use stop(warningToError(w)). If you call stop() with a condition argument then that is the condition stop() will signal, regardless of its class. I can't at the moment think of a good reason why I would want to call stop() with a warning condition argument, and I suspect most cases where that happens would be mistakes. So checking in stop() that a condition argument inherits from "error" and signaling a warning, or maybe an error, if it does not might be worth considering (with analogous changes for warning() and message()). The condition system separates the signaling protocol from the process of determining handlers. Signaling itself is done by signalCondition(). message() and warning() signal a condition with a muffle restart available, and return if the condition is not handled. stop() is guaranteed not to return; if the condition is not handled, then it invokes the default error handler, which will not return. None of these currently look at the class of the condition. signalCondition() looks at the condition's class to find out what handlers are available. It will invoke error handlers for error conditions and warning handlers for warning conditions. It does not know or care about whether it was called from stop(), warning(), message(), or some other way. The most common high-level usage of stop(), warning(), or message() is to call them with a string and possibly some additional arguments used to create a message. In these cases a condition object of class "error" for stop(), "warning" for warning(), and "message" for message is created implicitly and signaled. Calling these functions with a condition argument is using lower level functionality, which gives more power but also means users need to understand what they are doing. In particular, users who want to call stop() with a condition argument _and_ want handlers for error conditions to be used need to make sure that the class of the condition they signal inherits from "error". Best, luke On Tue, 1 Mar 2022, Andreas Kersting wrote:> Hi, > > There is the same issue with stop(): > >> w <- simpleWarning("careful") >> tryCatch(stop(w), condition = identity) > <simpleWarning: careful> > > I very recently stumbled upon this, when a warning was re-raised as an error, which was then not caught by an outer try(): > >> try( > + tryCatch(warning("careful"), warning = function(w) stop(w)), > + silent = TRUE > + ) > Error in doTryCatch(return(expr), name, parentenv, handler) : careful > > I would also like to see this behavior changed. I think that stop() should always signal an error, warning() a warning and message() a message. > > Best, > Andreas > > 2022-03-01 19:38 GMT+01:00 "Henrik Bengtsson" <henrik.bengtsson at gmail.com>: >> Hi, in help("message", package = "base"), we can read: >> >> Description: 'message' is used for generating 'simple' diagnostic >> messages which are neither warnings nor errors, but nevertheless >> represented as conditions. >> >> From this, I conclude that message() should generate a condition that >> are neither warning nor errors. >> >> However, the following signals a condition of class 'error': >> >>> e <- simpleError("boom!\n") >>> message(e) >> boom! >> >> This can be seen if we do: >> >>> res <- tryCatch(message(e), condition = identity) >>> res >> <simpleError: boom! >> >> This stems from message(e) using signalCondition(e) internally. >> >> Another problem with this behavior is that message(e) cannot be suppressed: >> >>> suppressMessages(message(e)) >> boom! >> >> or captured with calling handlers, e.g. >> >>> res <- withCallingHandlers(message(e), condition = identity) >> boom! >>> res >> NULL >> >> If we replace e <- simpleError("boom") with e <- >> simpleWarning("careful"), we see a similar behavior. These problems >> exist also with warning(e). The current behaviors prevent functions >> from capturing and relaying message(<error>), message(<warning>), and >> warning(<error>). >> >> I'm happy to post a bug report to <https://bugs.r-project.org/>. >> >> /Henrik >> >> PS. BTW, it looks like some recent "..." tweaks to the warning() and >> stop() code could be applied also to message(). >> >> ______________________________________________ >> R-devel at r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >-- Luke Tierney Ralph E. Wareham Professor of Mathematical Sciences University of Iowa Phone: 319-335-3386 Department of Statistics and Fax: 319-335-3017 Actuarial Science 241 Schaeffer Hall email: luke-tierney at uiowa.edu Iowa City, IA 52242 WWW: http://www.stat.uiowa.edu