[Rd] Bug: broken exception handling in S4 methods

From: Sklyar, Oleg (London) <osklyar_at_ahl.com>
Date: Wed, 21 Jul 2010 10:36:59 +0100


Hi all:

we have noticed for quite a while that certain errors cannot be handled by R try, tryCatch etc blocks, but it was fairly difficult to understand what were the conditions for this incorrect behaviour. Finally I stabbed across a very understandable case, which is outlined in the (runnable) example below.

The main message is: wrapping an S4 method call in a try block will not help if an error occurs in evaluating an argument to such a call; this works just fine for function calls (as opposed to S4 methods)

The particular example is a result of trying to write a unit test for a constructor of a class object which should fail under certain conditions. This failure obviously need to be caught for the unit test to proceed. However, it is a general problem with handling some exceptions in R.

# Consider a simple class MyClassA, which is derived from numeric and
for which
# we define a constructor (in form of a method). On its own this class
works nicely
# and so does exception handling of it:

setClass("MyClassA",

    contains = "numeric",
    validity = function(object)
    {

        stopifnot(object[1] == object[2])
        TRUE

    }
)

setGeneric("MyClassA", function(x) standardGeneric("MyClassA"))

setMethod("MyClassA",

    signature(x = "numeric"),
    function(x)
    {

        new("MyClassA", x)
    }
)

## OK
er = try({ MyClassA(c(1,2)) })

## OK (error in constructor)
er = try({ MyClassA(c(1,2)) })

## OK (error evaluating argument to a function) er = try({ sin(MyClassA(c(1,2))) })

# Now consider we define MyClassB that has MyClassA in a slot
# and we define a constructor that takes such objects:

setClassUnion("MyClassAOrNULL", c("MyClassA", "NULL"))

setClass("MyClassB",

    representation(

        ca = "MyClassAOrNULL"
    ),
    prototype(ca = NULL)
)

setGeneric("MyClassB", function(x) standardGeneric("MyClassB"))

setMethod("MyClassB",

    signature(x = "MyClassA"),
    function(x)
    {

        new("MyClassB", ca = x)
    }
)

## OK
b = MyClassB(MyClassA(c(1,1)))

## FAILS (error evaluating argument to a method) er = try({ MyClassB(MyClassA(c(1,2))) })

# As you see the last error cannot be handled

# Moreover. If we define a function and a method as function(x) x then
# the function can be handled by try, yet the method cannot:

f = function(x) x

setGeneric("g", function(x) standardGeneric("g")) setMethod("g", "MyClassA", function(x) x)

## OK (error evaluating argument to a function) er = try({ f(MyClassA(c(1,2))) })

## FAILS (error evaluating argument to a method) er = try({ g(MyClassA(c(1,2))) })

> sessionInfo()
R version 2.11.0 Patched (2010-05-05 r51914) x86_64-unknown-linux-gnu

locale:
 [1] LC_CTYPE=en_GB LC_NUMERIC=C LC_TIME=en_GB LC_COLLATE=en_GB

 [5] LC_MONETARY=C        LC_MESSAGES=en_GB    LC_PAPER=en_GB
LC_NAME=C           
 [9] LC_ADDRESS=C         LC_TELEPHONE=C       LC_MEASUREMENT=en_GB
LC_IDENTIFICATION=C attached base packages:
[1] splines   stats     graphics  utils     datasets  grDevices methods
base     


Dr Oleg Sklyar
Research Technologist
AHL / Man Investments Ltd
+44 (0)20 7144 3803
osklyar_at_ahl.com



 Please consider the environment before printing this email or its attachments. The contents of this email are for the named addressees ...{{dropped:19}}

R-devel_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Wed 21 Jul 2010 - 09:39:14 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Thu 22 Jul 2010 - 00:00:17 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel. Please read the posting guide before posting to the list.

list of date sections of archive