views:

67

answers:

5
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).

+2  A: 

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
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
See my edit (I forgot to clear `last.warning`). I don't think any of this is platform-specific.
Joshua Ulrich
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
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
+2  A: 

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
Yes I just started thinking of this myself :) it is a pain to code as well as inelegant
Alex Holcombe
A: 

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
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
Oh, damn, that's right. Something fishy is going on there.
VitoshKa
This looks like a bug to me. I would report it on r-devel.
VitoshKa
+1  A: 

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
Yes- a kludge but, to be honest, I use `<<-` a lot :)
Alex Holcombe
Another way is to use options. In any case some kind of "globality" is needed.
VitoshKa
A: 

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
You may also fancy returning the number of warnings as an attribute of the answer. `attr(ans, "number_of_warnings") <- .number_of_warnings`
Richie Cotton
Great! I can also grab the warning message in this way (`w`)
Alex Holcombe
You're welcome. Nothing says thank you like an upvote. :)
Richie Cotton