Inheritance of class S4 [(subset) with additional arguments

This is an extension of the Use of the call function NextMethod () in the accessor function in R.

Update 2017-03-25. To illustrate how this only happens when loading methods, but not when it is built into the package, I created a dummy package: https://github.com/zkamvar/inheritest#readme

Main problem:

I have a class panel that inherits another foo class, and both of them have extra arguments for the [. The foo method works sequentially, but the bar method does not work after the first use.

Error and tracking:

Error in callNextMethod(x, i, j, ..., drop): bad object found as method (class "function") 4: stop(gettextf("bad object found as method (class %s)", dQuote(class(method))), domain = NA) 3: callNextMethod(x, i, j, ..., drop) at #9 2: .local(x, i, j, ..., drop = drop) 1: BAR["x"] 

Additional Information:

I have a package that implements a class that depends on a class from another package. When packages are created, everything works fine, but when my package is just loaded (using devtools::load_all(".") ), I get the behavior below.

Minimum working example:


 foo <- setClass("foo", representation(x = "numeric", y = "numeric")) bar <- setClass("bar", representation(distance = "numeric"), contains = "foo") setMethod(f = "[", signature = signature(x = "foo", i = "ANY", j = "ANY", drop = "ANY"), definition = function(x, i, j, ..., foo = TRUE, drop = FALSE) { if (foo) message("FOOOOOOO") if (i == "x") { return( x@x ) } else { if (i == "y") { return( x@y ) } } }) #> [1] "[" setMethod(f = "[", signature = signature(x = "bar", i = "ANY", j = "ANY", drop = "ANY"), definition = function(x, i, j, ..., bar = TRUE, drop = FALSE) { if (bar) message("BAAAAAAR") if (i == "distance") { return( x@distance ) } else { callNextMethod(x, i, j, ..., drop) } }) #> [1] "[" FOO <- new("foo", x = 1, y = 4) BAR <- new("bar", x = 1, y = 4, distance = 3) FOO["x"] #> FOOOOOOO #> [1] 1 BAR["x"] #> BAAAAAAR #> FOOOOOOO #> [1] 1 FOO["x"] #> FOOOOOOO #> [1] 1 BAR["distance"] #> BAAAAAAR #> [1] 3 BAR["x"] # fails #> BAAAAAAR #> Error in callNextMethod(x, i, j, ..., drop): bad object found as method (class "function") BAR["x", foo = FALSE] #> BAAAAAAR #> [1] 1 

Note: when I passed this through reprex , the first and last BAR calls also led to errors, but I showed what I was experiencing in an interactive session. I am using R version 3.3.3

+5
source share
3 answers

This is due to the fact that callNextMethod() not smart enough to handle methods with primitives with extended forms. I corrected it and will soon hand over the chest.

+3
source

Here's a partial answer: this is related to "[" specifically. Here is some working code that replaces the '[' method with the 'bat' method. This works fine for me:

 foo <- setClass("foo", representation(x = "numeric", y = "numeric")) bar <- setClass("bar", representation(distance = "numeric"), contains = "foo") bat <- function (x, i, j, ..., drop = FALSE) message('in bat') setGeneric('bat') setMethod(f = "bat", signature = signature(x = "foo"), definition = function(x, i, j, ..., foo = TRUE, drop = FALSE) { if (foo) message("FOOOOOOO") if (i == "x") { return( x@x ) } else { if (i == "y") { return( x@y ) } } }) #> [1] "[" setMethod(f = "bat", signature = signature(x = "bar"), definition = function(x, i, j, ..., bar = TRUE, drop = FALSE) { if (bar) message("BAAAAAAR") if (i == "distance") { return( x@distance ) } else { callNextMethod(x, i, j, ..., drop) } }) FOO <- new("foo", x = 1, y = 4) BAR <- new("bar", x = 1, y = 4, distance = 3) bat(FOO, 'x') bat(BAR, 'distance') bat(BAR, 'x') 

And now:

 bat(FOO, 'x') FOOOOOOO [1] 1 bat(BAR, 'x') BAAAAAAR FOOOOOOO [1] 1 bat(BAR, 'distance') BAAAAAAR [1] 3 bat(BAR, 'x') BAAAAAAR FOOOOOOO [1] 1 

So, I think this is due to the interaction of S4 dispatching and [own dispatching ... and solutions? I have no one but to avoid S4, like a plague, as it seems. Maybe R-devel can help. Perhaps this is a real R error, given that the code only breaks into [ .

+1
source

The problem is probably due to the fact that [ is primitive, and primitives are processed differently when using S4 . Digging into callNextMethod shows that the column is not parsed correctly if the method has different arguments compared to the common one for this primitive function. If you drop the bar argument from a method definition, dispatching works correctly.

However, there is another workaround that does not require choosing a different function name. I add an additional function as.foo and remember the general one after conversion to the foo object:

 setGeneric("as.foo", function(x)standardGeneric("as.foo")) setMethod("as.foo", signature = "bar", function(x) new("foo", x = x@x , y = x@y )) setMethod(f = "[", signature = signature(x = "bar", i = "ANY", j = "ANY", drop = "ANY"), definition = function(x, i, j, ..., bar = TRUE, drop = FALSE) { if (bar) message("BAAAAAAR") if (i == "distance") { return( x@distance ) } else { x <- as.foo(x) callGeneric() } } ) 

Thus, you bypass hiccups in scheduling, and all the code that was used for failure now works

 FOO["x"] #> FOOOOOOO #> [1] 1 BAR["x"] #> BAAAAAAR #> FOOOOOOO #> [1] 1 BAR["distance"] #> BAAAAAAR #> [1] 3 BAR["x"] #> BAAAAAAR #> FOOOOOOO #> [1] 1 BAR["x", foo = FALSE] #> BAAAAAAR #> [1] 1 
+1
source

Source: https://habr.com/ru/post/1265688/


All Articles