Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using callNextMethod() within accessor function in R

This is related to the following post Problems passing arguments with callNextMethod() in R

I am writing accessors for two S4 classes, 'foo' and 'bar'. 'bar' inherits from foo and is extended only by a few slots. Instead of writing a full accessor function for objects of class 'bar' I want to pass the arguments to callNextMethod() when accessing a slot that is inherited by 'foo'. My code looks like this:

foo <- setClass("foo", representation(x = "numeric", y = "numeric"))
bar <- setClass("bar", representation(distance = "numeric"), contains = "foo")

setMethod("[", "bar", function(x, i, j, drop) {
  if (i == "distance") {
    return(x@distance)
    } else {
      callNextMethod()
    }
}
)

setMethod("[", "foo", function(x, i, j, drop) {
  if (i == "x") {
    return(x@x)
    } else {
      if (i == "y") {
        return(x@y)
      }
    }
}
)

Now let's try this:

f <- new("foo", x = 1, y = 2)
b <- new("bar", x = 3, y = 4, distance = 5)
f["x"]
f["y"]

The accessor for object 'f' of class 'foo' properly returns:

> f["x"]
[1] 1
> f["y"]
[1] 2

If I try to access the slot 'distance' of the object 'b' of class 'bar' the accessor also properly returns:

> b["distance"]
[1] 5

The problem occurs when I try to access any of the slots of the object 'b' of class 'bar' which are inherited from 'foo'. If I try:

b["x"]
b["y"]

I get the following error message:

Error in callNextMethod() : bad object found as method (class “function”)

I have read the recommendations from this post Problems passing arguments with callNextMethod() in R but I cannot define a generic for '[' and trying to pass the arguments explicitly to callNextMethod() also failed.

Surely I am doing something wrong! I have read several resources on inheritances and cannot identify the problem and I hope you folks will be able to guide me towards the right direction.

Thanks

Max

like image 781
Maxence Avatar asked Jul 21 '14 21:07

Maxence


1 Answers

Your methods both leave out one of the five formal arguments required by any [ method, namely the ellipsis (...).

args(getGeneric("["))
# function (x, i, j, ..., drop = TRUE) 
# NULL

Including it as a formal in both method definitions solves your problem:

setMethod("[", "bar", function(x, i, j, ..., drop) {
  if (i == "distance") {
    return(x@distance)
    } else {
      callNextMethod()
    }
}
)

setMethod("[", "foo", function(x, i, j, ..., drop) {
  if (i == "x") {
    return(x@x)
    } else {
      if (i == "y") {
        return(x@y)
      }
    }
}
)

b["distance"]
# [1] 5
b["x"]
# [1] 3
b["y"]
# [1] 4
like image 182
Josh O'Brien Avatar answered Nov 05 '22 18:11

Josh O'Brien