How to overload S4 slot selector `@` to be a generic function

≯℡__Kan透↙ 提交于 2021-02-09 08:49:06

问题


I am trying to turn the @ operator in R into a generic function for the S3 system.

Based on the chapter in Writing R extensions: adding new generic I tried implementing the generic for @ like so:

`@` <- function(object, name) UseMethod("@")
`@.default` <- function(object, name) base::`@`(object, name)

However this doesn't seem to work as it breaks the @ for the S4 methods. I am using Matrix package as an example of S4 instance:

Matrix::Matrix(1:4, nrow=2, ncol=2)@Dim

Error in @.default(Matrix::Matrix(1:4, nrow = 2, ncol = 2), Dim) : no slot of name "name" for this object of class "dgeMatrix"

How to implement a generic @ so it correctly dispatches in the case of S4 classes?


EDIT

Also interested in opinions about why it might not be a good idea?


回答1:


R's documentation is somewhat confusing as to whether @ is already a generic or not: the help page for @ says it is, but it isn't listed on the internalGenerics page.

The @ operator has specific behaviour as well as (perhaps) being a generic. From the help page for @: "It is checked that object is an S4 object (see isS4), and it is an error to attempt to use @ on any other object." That would appear to rule out writing methods for S3 classes, though the documentation is unclear if this check happens before method dispatch (if there is any) or after (whence it could be skipped if you supplied a specific method for some S3 class).

You can implement what you want by completely redefining what @ is, along the line of the suggestion in comments:

`@.default` <- function(e1,e2) slot(e1,substitute(e2))

but there are two reasons not to do this:

1) As soon as someone loads your package, it supersedes the normal @ function, so if people call it with other S4 objects, they are getting your version rather than the R base version.

2) This version is considerably less efficient than the internal one, and because of (1) you have just forced your users to use it (unless they use the cumbersome construction base::"@"(e1,e2)). Efficiency may not matter to your use case, but it may matter to your users' other code that uses S4.

Practically, a reasonable compromise might be to define your own binary operator %@%, and have the default method call @. That is,

`%@%` <- function(e1,e2) slot(e1,substitute(e2))
setGeneric("%@%")

This is called in practice as follows:

> setClass("testClass",slots=c(a="character")) -> testClass
> x <- testClass(a="cheese")
> x %@% a
[1] "cheese"


来源:https://stackoverflow.com/questions/52297071/how-to-overload-s4-slot-selector-to-be-a-generic-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!