Как перегрузить селектор слотов S4 `@` для универсальной функции - PullRequest
0 голосов
/ 12 сентября 2018

Я пытаюсь превратить оператор @ в R в универсальную функцию для системы S3.

На основе главы в Написание расширений R: добавление нового универсального Я пыталсяреализация обобщенного для @, например, так:

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

Однако, похоже, это не сработает, поскольку нарушает @ для методов S4.Я использую Matrix пакет в качестве примера экземпляра S4:

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

Ошибка в @.default (Matrix :: Matrix (1: 4, nrow = 2, ncol = 2),Dim): нет слота с именем «name» для этого объекта класса «dgeMatrix»

Как реализовать универсальный @, чтобы он правильно отправлялся в случае классов S4?


РЕДАКТИРОВАТЬ

Также интересует мнение о том, почему это не может быть хорошей идеей?

1 Ответ

0 голосов
/ 14 сентября 2018
Документация

R несколько сбивает с толку относительно того, является ли @ уже универсальным или нет: на странице справки для @ сказано, что это так, но его нет на странице internalGenerics.

Оператор @ имеет специфическое поведение, а также (возможно) является универсальным. На странице справки для @: «Проверено, что объект является объектом S4 (см. IsS4), и попытка использовать @ для любого другого объекта является ошибкой». Казалось бы, это исключает написание методов для классов S3, хотя в документации неясно, происходит ли эта проверка перед отправкой метода (если она есть) или после (откуда она может быть пропущена, если вы предоставили определенный метод для некоторого класса S3).

Вы можете реализовать то, что хотите, полностью переопределив, что такое @, в соответствии с предложением в комментариях:

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

но есть две причины не делать этого:

1) Как только кто-то загружает ваш пакет, он заменяет обычную функцию @, поэтому, если люди вызывают его с другими объектами S4, они получают вашу версию, а не базовую версию R.

2) Эта версия значительно менее эффективна, чем внутренняя, и из-за (1) вы просто заставили ее использовать своих пользователей (если они не используют громоздкую конструкцию base::"@"(e1,e2)). Эффективность может не иметь значения для вашего варианта использования, но может иметь значение для другого кода ваших пользователей, который использует S4.

Практически разумным компромиссом может быть определение собственного двоичного оператора %@% и вызов метода по умолчанию @. То есть

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

На практике это называется следующим образом:

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