TryCatch не ломает ошибку, если вызвана, хотя RScript

У меня возникла странная проблема в R.

Рассмотрим следующий код (действительно упрощенная версия реального кода, но все еще проблема):

library(timeSeries)

tryCatch(
{
  specificWeekDay <- 2

  currTs <- timeSeries(c(1,2),c('2012-01-01','2012-01-02'),
                       format='%Y-%m-%d',units='A')
  # just 2 dates out of range
  start <- time(currTs)[2]+100*24*3600
  end <- time(currTs)[2]+110*24*3600

  # this line returns an empty timeSeries
  currTs <- window(currTs,start=start,end=end)

  message("Up to now, everything is OK")

  # this is the line with the uncatchable error
  currTs[!(as.POSIXlt(time(currTs))$wday %in% specificWeekDay),] <- NA

  message("I'm after the bugged line !")

},error=function(e){message(e)})

message("End")

Когда я запускаю этот код в RGui, я правильно получаю следующий вывод:

До сих пор все в порядке
ошибка при оценке аргумента 'i' в выбор метода для функции '[< -': Ошибка в as.POSIXlt.numeric(time (currTs)): необходимо указать "origin"
Конец

Вместо этого, когда я запускаю его через RScript (в окнах), используя следующую строку:

RScript.exe --vanilla "myscript.R"

Я получаю этот вывод:

До сих пор все в порядке
Выполнение прервано

Кажется, что сбой RScript...

Любая идея о причине?
Является ли это ошибкой пакета timeSeries, или я делаю что-то неправильно?
Если последний, какой правильный способ наверняка поймать все ошибки?

Спасибо заранее.


EDIT:

Ниже приведен пример, воспроизводящий проблему, которая не использует пакет timeSeries. Чтобы проверить его, просто запустите его, как описано выше:

library(methods)
# define a generic function
setGeneric("foo", 
           function(x, ...){standardGeneric("foo")})
# set a method for the generic function
setMethod("foo", signature("character"),
          function(x) {x})
tryCatch(
{
  foo("abc")
  foo(notExisting)
},error=function(e)print(e))

Кажется, что-то связано с диспетчеризацией общего метода; когда аргумент метода вызывает ошибку, диспетчер не может найти подпись метода и последовательно вызывает исключение, которое функция tryCatch кажется неспособной обрабатывать при запуске через RScript.
Как ни странно, это не происходит, например, с print(notExisting); в этом случае исключение корректно обрабатывается.

Любая идея о причине и как поймать такие ошибки?

Примечание:
Я использую R-2.14.2 в Windows 7

Ответы

Ответ 1

Проблема заключается в том, как внутренний C-код, реализующий S4-метод отправки, пытается поймать и обработать некоторые ошибки и как неинтерактивный случай обрабатывается в этом подходе. В R-devel и R-patched в ближайшее время должно быть организовано обход.

Работа вокруг теперь привязана к R-devel и R-patched.

Ответ 2

Информация о tryCatch() [что OP уже знал и использовал, но я не заметил]

Я думаю, что вам не хватает того, что ваш tryCatch() не делает ничего особенного с ошибкой, поэтому вы поднимаете ошибку в обычном режиме. В интерактивном использовании ошибка генерируется и обрабатывается обычным способом, но ошибка внутри script, выполняемая в неинтерактивном сеансе (a la Rscript), прервет работу script.

tryCatch() - сложная функция, которая позволяет потенциально захватывать и обрабатывать всевозможные события в R, а не только ошибки. Однако по умолчанию он настроен для имитации стандартной процедуры обработки ошибок R; в основном, позволяют вызывать ошибку и сообщаться R. Если вы хотите, чтобы R выполнял что-либо иное, кроме основного поведения, вам нужно добавить определенный обработчик для ошибки:

> e <- simpleError("test error")
> tryCatch(foo, error = function(e) e,
+          finally = writeLines("There was a problem!"))
There was a problem!
<simpleError in doTryCatch(return(expr), name, parentenv, handler): object 'foo'
not found>

Я предлагаю вам более подробно прочитать ?tryCatch, чтобы лучше понять, что он делает.

Альтернативой является использование try(). Чтобы изменить ваш script, я бы просто сделал:

# this is the line with the uncatchable error
tried <- try(currTs[!(as.POSIXlt(time(currTs))$wday %in% specificWeekDay),] <- NA,
             silent = TRUE)
if(inherits(tried, "try-error")) {
    writeLines("There was an error!")
} else {
    writeLines("Everything worked fine!")
}

Ключевым битом является сохранение объекта, возвращаемого с try(), чтобы вы могли протестировать класс и чтобы try() работал молча. Рассмотрим разницу:

> bar <- try(foo)
Error in try(foo) : object 'foo' not found
> bar <- try(foo, silent = TRUE)
> class(bar)
[1] "try-error"

Обратите внимание, что в первом вызове выше ошибка поймана и как сообщение. Во втором случае это не сообщается. В обоих случаях возвращается объект класса "try-error".

Внутренне, try() записывается как один вызов tryCatch(), который настраивает пользовательскую функцию для обработчика ошибок, который сообщает об ошибке как сообщении и настраивает возвращенный объект. Возможно, вы захотите изучить код R для try() как еще один пример использования tryCatch().