8
op <- options(warn=0)  #although doesn't work for any value of warn
assign("last.warning", NULL, envir = baseenv())  
thisDoesntWork<- function() {
warning("HEY, this is definitely a warning!")
cat(paste("number of warnings:",length(warnings())))
}   
>thisDoesntWork()
Warning in thisDoesntWork() : HEY, this is definitely a warning!
number of warnings: 0

Number of warnings should be 1 rather than 0 - it seems that warnings() returns nothing if called within a function. Why? How can one work around this to check within a function if warnings occurred, and print them out?

I don't want to use tryCatch, because then I lose the value that the function returns (it may still return a valid value, even if it generated a warning).

Alex Holcombe
  • 2,453
  • 4
  • 24
  • 34

5 Answers5

5

Here's the code for suppressWarnings

function (expr) 
{
    withCallingHandlers(expr, warning = function(w) invokeRestart("muffleWarning"))
}

I've tweaked it a little to count the number of warnings instead.

countWarnings <- function(expr) 
{
    .number_of_warnings <- 0L
    frame_number <- sys.nframe()
    ans <- withCallingHandlers(expr, warning = function(w) 
    {
      assign(".number_of_warnings", .number_of_warnings + 1L, 
        envir = sys.frame(frame_number))
      invokeRestart("muffleWarning")
    })
    message(paste("No. of warnings thrown:", .number_of_warnings))
    ans
}

A test:

countWarnings(log(-1))
No. of warnings thrown: 1
[1] NaN

Another test:

foo <- function()
{
  warning("first warning!")
  warning("second warning!")
  warning("third warning!")
  invisible()
}
countWarnings(foo())
No. of warnings thrown: 3
NULL
Richie Cotton
  • 118,240
  • 47
  • 247
  • 360
2

Your example does return a warning.

> assign("last.warning", NULL, envir = baseenv())  
> thisDoesntWork <- function() {
+   warning("HEY, this is definitely a warning!")
+   cat(paste("number of warnings:",length(warnings())),"\n")
+ }
> thisDoesntWork()
number of warnings: 0 
Warning message:
In thisDoesntWork() : HEY, this is definitely a warning!
> warnings()  # HEY, here's your warning!!!
Warning message:
In thisDoesntWork() : HEY, this is definitely a warning!

The documentation isn't explicit, but I don't think last.warning gets set until the call finishes (especially given the call is part of what can be returned).

Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • thanks, as you see in mine where it spit out "number of warnings:0" it doesn't work on my machine- OSX with R 2.11.1 GUI 1.34 Leopard build 32-bit (5589). Hm what should I try now? – Alex Holcombe Oct 26 '10 at 02:38
  • See my edit (I forgot to clear `last.warning`). I don't think any of this is platform-specific. – Joshua Ulrich Oct 26 '10 at 02:41
  • If you're right about `last.warning` not being set until return, then I'm stuck. Within a function, how can I determine whether a warning occurred, without losing the value to be returned by the function? Using `tryCatch` catches the warnings of course, but seems to lose the value the function would have returned if not embedded in a `tryCatch` – Alex Holcombe Oct 26 '10 at 02:56
  • 1
    The use of warnings() is tied to options('warn') (read ?options) and as Joshua hinted, it gets set at the end of a REPL iteration. I found this out when I just recently cleaned up rApache's error logging code. The solution is to wrap your code in tryCatch and implement your own warning handlers to count the number of handlers that have occurred. – Jeff Oct 26 '10 at 14:07
2

probably this is a very very bad workaround...

fw<-function(){warning("warn...");return(99)}
fn<-function(){return(88)}

f<-function(){
    w<-0
    v<-NULL
    v<-tryCatch(fw(),warning=function(w){w})
    if("warning"%in%class(v)){
        w<-w+1 # e.g., count up the number of warning
        v<-fw()
    }
    print(v)

    v<-NULL
    v<-tryCatch(fn(),warning=function(w){w})
    if("warning"%in%class(v)){
        w<-w+1 # e.g., count up the number of warning
        v<-fn()
    }
    print(v)
}
f()

calling the function twice if warning occurs... though I believe that there must be more elegant solutions

kohske
  • 65,572
  • 8
  • 165
  • 155
1

Here is a workaround

..my_warning <- 0L

thisDoesWork<- function(){
    assign("last.warning", NULL, envir = baseenv())  
    warning("HEY, this is definitely a warning!", {..my_warning <<- ..my_warning+1L;""})
    str(last.warning)
    cat(paste("number of warnings:", ..my_warning, "\n"))
}


thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 1 
>     thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 2 
>     thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 3 
> 
VitoshKa
  • 8,387
  • 3
  • 35
  • 59
0

The warnings are issued not before the function returns. See the documentation for options("warn"):

options(warn=1L)
thisDoesntWork()
#Warning in thisDoesntWork() : HEY, this is definitely a warning!
#number of warnings: 1 
VitoshKa
  • 8,387
  • 3
  • 35
  • 59
  • Like the first person to answer, I think you may have forgotten to call assign("last.warning", NULL, envir = baseenv()) first. If so, that 1 warning the function finds is from a previous call.. – Alex Holcombe Oct 26 '10 at 08:35
  • This looks like a bug to me. I would report it on r-devel. – VitoshKa Oct 26 '10 at 09:42