R 如何捕获S4方法选择期间发送的警告

R 如何捕获S4方法选择期间发送的警告,r,warnings,s4,R,Warnings,S4,使用调用处理程序的无法捕获S4通用函数的求值参数时生成的警告 WithCallingHandler的正常行为说明: ### simple function that sends a warning send_warning <- function() { warning('send_warning') } send_warning() # Warning message: # In send_warning() : send_warning ### the warning can b

使用调用处理程序的无法捕获S4通用函数的求值参数时生成的警告

WithCallingHandler的正常行为说明:

### simple function that sends a warning
send_warning <- function() {
  warning('send_warning')
}
send_warning()
# Warning message:
# In send_warning() : send_warning

### the warning can be caught by withCallingHandlers
withCallingHandlers(send_warning(), warning = function(w) 
  { stop('got warning:', w) })
# Error in (function (w)  : 
#   got warning:simpleWarning in send_warning(): send_warning
最后一个示例显示在S4方法调用期间不会发生这种情况:

setGeneric('my_method2', function(x) standardGeneric('my_method2') )
setMethod('my_method2', 'ANY', function(x) warning('my_method2') )
my_method2()
# Warning message:
# In my_method2() : my_method2

### warning is caught
withCallingHandlers(my_method2(), warning = function(w) 
  { stop('got warning:', w) })
# Error in (function (w)  : 
#   got warning:simpleWarning in my_method2(): my_method2

据我所知,S4调度期间发出的警告似乎有一种特殊的行为。我想知道为什么以及如何抓住它们

我最初的猜测是,这是因为方法分派会抑制警告

f = function(x) withCallingHandlers(x, warning=function(w) { 
    cat('muffled\n')
    invokeRestart("muffleWarning")
})
然后

> withCallingHandlers(f(warning("f")), warning=function(w) message("caught"))
muffled
深入挖掘,实际的警告调用在这个C堆栈跟踪中

#0  do_warning (call=0x3d4ad50, op=0x9c4bf0, args=0x45b9968, rho=0x45b9c40) at /home/mtmorgan/src/R-devel/src/main/errors.c:1140
#1  0x00000000004b4198 in bcEval (body=<optimized out>, rho=<optimized out>, useCache=<optimized out>) at /home/mtmorgan/src/R-devel/src/main/eval.c:4700
#2  0x00000000004bff40 in Rf_eval (e=0x3d45618, rho=0x45b9c40) at /home/mtmorgan/src/R-devel/src/main/eval.c:554
#3  0x00000000004c4e4d in Rf_applyClosure (call=0x45b8630, op=0x3d45730, arglist=<optimized out>, rho=0x9e7638, suppliedenv=0x9e7670) at /home/mtmorgan/src/R-devel/src/main/eval.c:1033
#4  0x00000000004c0005 in Rf_eval (e=0x45b8630, rho=0x9e7638) at /home/mtmorgan/src/R-devel/src/main/eval.c:670
#5  0x00000000004c0695 in forcePromise (e=0x45b9410) at /home/mtmorgan/src/R-devel/src/main/eval.c:458
#6  0x00000000004c0462 in Rf_eval (e=0xa1d338, rho=0x45b9368) at /home/mtmorgan/src/R-devel/src/main/eval.c:577
#7  0x000000000046fbfb in protectedEval (d=0x7fffffffc7f0) at /home/mtmorgan/src/R-devel/src/main/context.c:750
#8  0x0000000000470d48 in R_ToplevelExec (fun=0x46fbe0 <protectedEval>, data=0x7fffffffc7f0) at /home/mtmorgan/src/R-devel/src/main/context.c:705
#9  0x0000000000470de7 in R_tryEval (e=<optimized out>, env=<optimized out>, ErrorOccurred=0x7fffffffc89c) at /home/mtmorgan/src/R-devel/src/main/context.c:764
#10 0x0000000000470e26 in R_tryEvalSilent (e=<optimized out>, env=<optimized out>, ErrorOccurred=<optimized out>) at /home/mtmorgan/src/R-devel/src/main/context.c:787
#11 0x00007ffff49230b9 in R_dispatchGeneric (fname=0x44b37e8, ev=0x45b9368, fdef=0x45b92f8) at /home/mtmorgan/src/R-devel/src/library/methods/src/methods_list_dispatch.c:993
#12 0x00000000004f5337 in do_standardGeneric (call=<optimized out>, op=<optimized out>, args=<optimized out>, env=0x45b9368) at /home/mtmorgan/src/R-devel/src/main/objects.c:1167
....
这样做似乎是为了实现C级错误处理程序:

998         if(check_err)
999         error(_("error in evaluating the argument '%s' in selecting a method for function '%s': %s"),
1000                  CHAR(PRINTNAME(arg_sym)),CHAR(asChar(fname)),
1001                  R_curErrorBuf());
Rf_tryEvalSilent
在顶层求值,类似于在命令提示符下没有建立调用处理程序;您可以在C代码中看到这一点,其中处理程序堆栈设置为NULL

686 Rboolean R_ToplevelExec(void (*fun)(void *), void *data)
687 {
688     RCNTXT thiscontext;
689     RCNTXT * volatile saveToplevelContext;
690     volatile SEXP topExp, oldHStack;
691     Rboolean result;
692 
693 
694     PROTECT(topExp = R_CurrentExpr);
695     PROTECT(oldHStack = R_HandlerStack);
696     R_HandlerStack = R_NilValue;
697     saveToplevelContext = R_ToplevelContext;
由于参数计算是在没有处理程序的情况下开始的,因此可能需要一种变通方法

my_method(withCallingHandlers(warning('arrgh'), warning=function(w) ...))

但这可能不太实际。

我模糊地记得看到R-dev邮件列表上讨论过这一点或类似的事情……你知道有没有很好的理由进行射频测试,而不是实际使用调用处理程序的某种评估?这些问题只能由
packageDescription(“方法”)$Maintainer(“方法”)
(您已经问过了…)来回答,但从代码来看,这似乎是为了添加C级错误处理程序而实现的(!);在其他情况下,这可能是为了在错误发生后但在返回给用户之前进行C级清理。
686 Rboolean R_ToplevelExec(void (*fun)(void *), void *data)
687 {
688     RCNTXT thiscontext;
689     RCNTXT * volatile saveToplevelContext;
690     volatile SEXP topExp, oldHStack;
691     Rboolean result;
692 
693 
694     PROTECT(topExp = R_CurrentExpr);
695     PROTECT(oldHStack = R_HandlerStack);
696     R_HandlerStack = R_NilValue;
697     saveToplevelContext = R_ToplevelContext;
my_method(withCallingHandlers(warning('arrgh'), warning=function(w) ...))