S4 class [(子集)带有附加参数的继承
S4 class [ (subset) inheritance with additional arguments
这是 Using callNextMethod() within accessor function in R 的扩展。
2017-03-25 更新:为了说明这仅在加载方法时失败,而不是在构建包中时失败,我创建了一个虚拟包:https://github.com/zkamvar/inheritest#readme
基本问题:
我有一个 class bar 继承了另一个 class foo,并且它们都有用于 [ 方法的附加参数。 foo 的方法始终有效,但 bar 的方法在第一次使用后失败。
错误和回溯:
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"]
更多详情:
我有一个实现 class 的包,它依赖于来自另一个包的 class。构建包时,一切正常,但是当我的包被简单加载时(使用 devtools::load_all(".")
),我得到以下行为。
最小工作示例:
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
注意:当我通过 reprex 传递它时,对 BAR 的第一次和最后一次调用也导致了错误,但我展示了我在交互式会话中的体验。我正在使用 R 版本 3.3.3
这是一个部分答案:它专门与“[”有关。这是一些工作代码,它用 'bat' 方法替换了 '[' 方法。它对我来说很好用:
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')
现在:
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
所以,我认为这与 S4 调度和 [自己的调度...以及解决方案的交互有关?我有 none,只是为了避免像瘟疫一样的 S4。也许 R-devel 可以提供帮助。这可能是一个真正的 R 错误,因为代码仅在 [
.
时中断
这个问题可能与 [
是原语有关,而使用 S4
时原语的处理方式不同。深入研究 callNextMethod
表明,在该方法与该原始函数的泛型相比具有不同参数的情况下,调用堆栈未被正确分析。如果从方法定义中删除参数 bar
,则分派工作正常。
也就是说,还有另一种解决方法,不需要您选择其他函数名称。我添加了一个额外的函数 as.foo
并在转换为 foo 对象后调用泛型:
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()
}
}
)
通过这种方式,您可以避免调度中的问题,并且所有以前失败的代码现在都可以工作了
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
这是因为 callNextMethod()
不够智能,无法处理具有增强形式的基元上的方法。我已经修好了,很快就会提交到 trunk。
这是 Using callNextMethod() within accessor function in R 的扩展。
2017-03-25 更新:为了说明这仅在加载方法时失败,而不是在构建包中时失败,我创建了一个虚拟包:https://github.com/zkamvar/inheritest#readme
基本问题:
我有一个 class bar 继承了另一个 class foo,并且它们都有用于 [ 方法的附加参数。 foo 的方法始终有效,但 bar 的方法在第一次使用后失败。
错误和回溯:
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"]
更多详情:
我有一个实现 class 的包,它依赖于来自另一个包的 class。构建包时,一切正常,但是当我的包被简单加载时(使用 devtools::load_all(".")
),我得到以下行为。
最小工作示例:
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
注意:当我通过 reprex 传递它时,对 BAR 的第一次和最后一次调用也导致了错误,但我展示了我在交互式会话中的体验。我正在使用 R 版本 3.3.3
这是一个部分答案:它专门与“[”有关。这是一些工作代码,它用 'bat' 方法替换了 '[' 方法。它对我来说很好用:
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')
现在:
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
所以,我认为这与 S4 调度和 [自己的调度...以及解决方案的交互有关?我有 none,只是为了避免像瘟疫一样的 S4。也许 R-devel 可以提供帮助。这可能是一个真正的 R 错误,因为代码仅在 [
.
这个问题可能与 [
是原语有关,而使用 S4
时原语的处理方式不同。深入研究 callNextMethod
表明,在该方法与该原始函数的泛型相比具有不同参数的情况下,调用堆栈未被正确分析。如果从方法定义中删除参数 bar
,则分派工作正常。
也就是说,还有另一种解决方法,不需要您选择其他函数名称。我添加了一个额外的函数 as.foo
并在转换为 foo 对象后调用泛型:
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()
}
}
)
通过这种方式,您可以避免调度中的问题,并且所有以前失败的代码现在都可以工作了
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
这是因为 callNextMethod()
不够智能,无法处理具有增强形式的基元上的方法。我已经修好了,很快就会提交到 trunk。