[Rd] Bug: broken exception handling in S4 methods

Sklyar, Oleg (London) osklyar at ahl.com
Wed Jul 21 11:36:59 CEST 2010


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}}



More information about the R-devel mailing list