2013-11-28 18 views
7

Uyarılar gönderilen uyarıları yakalamak için nasıl oluşturulan S4 jenerik fonksiyonlarının değerlendirilmesi argümanlar withCallingHandlers kullanılarak yakalandı edilemez zaman(). withCallingHandlers normal davranışS4 yöntemi seçimi sırasında

İllüstrasyon: Bu sırasında olmamasını göstermek için

### simplest method ever 
setGeneric('my_method', function(x) standardGeneric('my_method')) 
setMethod('my_method', 'ANY', function(x) str(x)) 

### call it with an argument that produces a warning: seems to work 
my_method(warning('argh')) 
# chr "argh" 
# Warning message: 
# argh 

### !!! BUT it is not caught !!!!!!!!!!!!!!!!!!: 
withCallingHandlers(my_method(warning('argh')), warning = function(w) 
    { stop('got warning:', w) }) 
# chr "argh" 
# Warning message: 
# argh 

Son bir örnek: Şimdi

### 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 

, uyarısı bir S4 sevk sırasında yayılması yapalım S4 yöntemi çağrısı:

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 

Anladığım kadarıyla var gibi görünüyor. S4 dağıtımı sırasında yayınlanan uyarıların özel davranışı. Onları neden ve nasıl yakalayacağını bilmek isterim.

+0

R-dev e-posta listesinde tartışılan, bunu ya da bunun gibi bir şey görmenin belirsiz bir anımsaması var ... – Spacedman

cevap

3

Benim asıl tahminim yöntemi sevk derin Kazı uyarıları

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

ve sonra

> withCallingHandlers(f(warning("f")), warning=function(w) message("caught")) 
muffled 

muffles çünkü bu olduğunu idi fiili uyarı çağrısı bu C yığın izleme olduğunu

#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 
.... 

Burada C kodu R_dispatchGeneric yönteminin gönderilmesinde g değerlendirerek tartışmanın sınıfını anlamaya o

989   if(arg_sym == R_dots) { 
990   thisClass = dots_class(ev, &check_err); 
991   } 
992   else { 
993   PROTECT(arg = R_tryEvalSilent(arg_sym, ev, &check_err)); 
994   if(!check_err) 
995    thisClass = R_data_class(arg, TRUE); 
996   UNPROTECT(1); /* for arg */ 
997   } 

Bu bir C-seviyesinde bir hata işleyicisi uygulamak için yapılması gereken görünüyor: gbi

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 üst düzeyde değerlendirir şey çağrı yapan işleyicilerin bulunmadığı komut istemi; argüman değerlendirme işleyicileri olmadan başlar beri bir-etrafında çalışma

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

olabilir, işleyici yığını

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; 

NULL olarak ayarlanır C kodu, bu görebilirsiniz ama muhtemelen pratik değil.

+0

Bir Rf_tryEvalSilent yapmak için iyi bir neden olup olmadığını biliyor musunuz, aslında çağrı işleyicilerini kullanır mı? –

+0

Bu sorular sadece 'packageDescription() yöntemleri') tarafından cevaplandırılabilir $ Maintainer' (daha önce sormuştunuz ...) ama bu koddan C-level hata işleyicisi eklemek için uygulanmış gibi görünüyor. !); Diğer durumlarda bu, bir hata oluştuğunda ancak kullanıcıya dönmeden önce C seviyesini temizlemek için yapılabilir. –