9

Why does R throw the error "Error in value[3L] : no loop for break/next, jumping to top level" instead of going to the next iteration of a loop? I'm on R version 2.13.1 (2011-07-08)

for (i in seq(10)) { 
   tryCatch(stop(), finally=print('whoops'), error=function(e) next) 
}

This problem came up because I wanted to create a different image or no image at all when plot failed. The code, using joran's approach, would look like this:

for (i in c(1,2,Inf)) { 
   fname = paste(sep='', 'f', i, '.png')
   png(fname, width=1024, height=768) 
   rs <- tryCatch(plot(i), error=function(e) NULL)
   if (is.null(rs)){
    print("I'll create a different picture because of the error.")
   }
   else{
    print(paste('image', fname, 'created'))
    dev.off()
    next
   } 
}
selden
  • 333
  • 2
  • 6
  • 12
  • 3
    For visitors to this question trying to find a more generic answer to "Why does R say no loop for break/next, jumping to top level", this answer here does a great job covering it: https://stackoverflow.com/a/34405776/1454785 – spops Feb 20 '20 at 15:20
  • I feel like a solution with `eval(expr = next, envir = parent.frame(n = 1))` or something similar should work, but I wasn't able to get it to work. Maybe someone else will know. – CoderGuy123 Mar 05 '20 at 14:15

3 Answers3

13

Maybe you could try :

for (i in seq(10)) { 
   flag <- TRUE
   tryCatch(stop(), finally=print('whoops'), error=function(e) flag<<-FALSE)
   if (!flag) next
}
Simon
  • 164
  • 3
5

Unfortunately, once you get inside your error function you're no longer in a loop. There's a way you could hack around this:

for (i in seq(10)) { 
   delayedAssign("do.next", {next})
   tryCatch(stop(), finally=print('whoops'),
        error=function(e) force(do.next))
}

Though that is... well, hacky. Perhaps there is a less hacky way, but I don't see one right off.

(This works because delayedAssign happens every loop, canceling out the efforts of force)

EDIT

Or you could use continuations:

for (i in seq(10)) { 
   callCC(function(do.next) {
       tryCatch(stop(), finally=print('whoops'),
           error=function(e)    do.next(NULL))
       # Rest of loop goes here
       print("Rest of loop")
   })
}

EDIT

As Joris points out, you probably shouldn't actually use either of these, because they're confusing to read. But if you really want to call next in a loop, this is how :).

Owen
  • 38,836
  • 14
  • 95
  • 125
  • yeah they both seem to work for me. Although I didn't say so this code is supposed to not create a png if the plot command fails. Maybe I have set it up wrong. plot would go where stop is. – selden Aug 11 '11 at 23:01
  • +1 good explanation, although I would strongly advise against your constructs. There are far better programming flows that can result in the same, without hacking around. Putting what you want to do in an internal function, and wrapping that in the tryCatch for example. – Joris Meys Aug 11 '11 at 23:33
  • @Joris yes, you're really right. I was just intrigued by the idea of calling `next` from within a function. I'll add a note apologizing for me insanity ;) – Owen Aug 11 '11 at 23:40
3

Wouldn't it make more sense to put the next outside the tryCatch based on an if check? Something like this:

for (i in c(1,2,Inf)) { 
   rs <- tryCatch(seq(i), finally=print('whoops'), error=function(e) NULL)
   if (is.null(rs)){
    print("I found an error!")
   }
   else{
    next
   } 
}

although I'm not sure this is what you want, since I'm a little unclear on what you're trying to do.

EDIT

Based on the OP's revisions, this formulation works for me:

plotFn <- function(fname,i){
    png(fname, width=400, height=200)
    plot(i)
    dev.off()
}


for (i in c(1,Inf,3)) { 
   fname = paste('f', i, '.png',sep="")
   rs <- tryCatch(plotFn(fname,i), error=function(e){dev.off(); return(NULL)})
   if (is.null(rs)){
    print("I'll create a different picture because of the error.")
   }
   else{
    print(paste('image', fname, 'created'))
    next
   } 
}

I'm certain that not having a dev.off() call in the case of an error needed to be fixed. I'd have to dig a little deeper to figure out exactly why separating png and plot was causing problems. But I think it's probably cleaner to keep the png(); plot(); dev.off() sequence self contained anyway. Also note that I put a dev.off() in the error function.

I haven't tested what will happen if plotFn throws an error on png(), never creates the device and then reaches the error function and calls dev.off(). Behavior may depend on what else you have going on in your R session.

joran
  • 169,992
  • 32
  • 429
  • 468
  • I editted the question to use your code to do what I'm trying to do. Notice it doesn't quite work as plot throws an error every time. – selden Aug 12 '11 at 17:22