[Rd] [External] Re: message(<cond>) and warning(<cond>) circumvent calling handlers and signal the original class, e.g. an error

iuke-tier@ey m@iii@g oii uiow@@edu iuke-tier@ey m@iii@g oii uiow@@edu
Wed Mar 2 00:12:45 CET 2022


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 using 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 using r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
> ______________________________________________
> R-devel using 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 using uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



More information about the R-devel mailing list