Множественная диспетчеризация для методов `subset` в R

Я разрабатываю пакет и хочу написать два метода подмножества для объектов пользовательского класса myclass с отправкой по двум аргументам, первый из которых является объектом для подмножества класса myclass, а второй является либо логическим вектором символов, например так:

setMethod(
    f = "subset",
    signature = c(x = "myclass", subset = "logical"),
    definition = function(x, subset){
            # function body 
    }
)

setMethod(
    f = "subset",
    signature = c(x = "myclass", subset = "character"),
    definition = function(x, subset){ 
        # different function body 
    }
)

Однако я не могу этого сделать, потому что универсальный S3 отправляет только один аргумент. И я не хочу создавать новый дженерик для subset, потому что он будет маскировать существующий дженерик при загрузке моего пакета. Я думаю, что одним из способов решения этой проблемы было бы создание дженерика и методов с разными именами, но это было бы не очень интуитивно понятно для пользователей, верно? Итак, я что-то упускаю/не понимаю, и есть ли какой-нибудь остроумный способ иметь несколько диспетчеров для дженериков S3?


person anamaria    schedule 18.03.2018    source источник
comment
Вам может понадобиться S4 или, возможно, ссылочные классы (одна хорошая ссылка: adv-r.had .co.nz/OO-essentials.html).   -  person r2evans    schedule 18.03.2018
comment
В противном случае вам может потребоваться внутренняя обработка второго типа аргумента.   -  person r2evans    schedule 18.03.2018
comment
Так что нельзя написать методы S4 для универсального S3? Спасибо за предложение, я не думал обрабатывать это в методе, но это, безусловно, способ обойти проблему.   -  person anamaria    schedule 18.03.2018
comment
S3 срабатывает по первому аргументу. Период. Если вы хотите большего, вам нужно выбрать что-то другое, кроме S3. S4 обеспечивает больший контроль, как и эталонные классы и R6. В рамках метода эффективно повторно реализуются некоторые из причин, по которым были созданы S4 и другие, и иногда это может быть наименее болезненным вариантом. Если вы считаете, что в будущем произойдет расширение, я могу предложить склоняться к более надежным альтернативам; если это почти наверняка единичный случай, а потребности в обслуживании в будущем очень ограничены, то, возможно, внутренней реализации будет достаточно.   -  person r2evans    schedule 19.03.2018
comment
@anamaria привет! Эмуляция множественной отправки с помощью S3 давно была тем, что я хотел сделать как можно лучше. Есть ли у вас новости о том, что сработало лучше всего для вас? Также нашел этот суть Уинстона Чанга   -  person Rappster    schedule 09.09.2019
comment
@Rappster Я нашел подход, предложенный в ответе JDL, достаточным для моей ситуации, и пока я не нашел ничего более подходящего.   -  person anamaria    schedule 13.09.2019
comment
@anamaria спасибо, что ответили мне на этот вопрос. Хотя мне в целом нравится уровень сложности S4, я не хочу покидать мир S3. На самом деле я придумал подход мой собственный. Далеко не приятно, но это работает, и это S3 ;-)   -  person Rappster    schedule 13.09.2019


Ответы (1)


Обычно в этой ситуации вы бы установили subset в качестве универсального S4, но, поскольку у вас есть причины не хотеть этого делать, вы можете обойти это, определив отдельный универсальный метод и вызвав его из метода S3, по аналогии с

mySubset <- function(x,subset){
  stop("this is only a generic function: it should never be called!")
}
setGeneric("mySubset")
## methods for mySubset
setMethod(
    f = "mySubset",
    signature = c(x = "myclass", subset = "logical"),
    definition = function(x, subset){
            # function body 
    }
)

setMethod(
    f = "mySubset",
    signature = c(x = "myclass", subset = "character"),
    definition = function(x, subset){ 
        # different function body 
    }
)

## default method using "ANY" (lower priority)
setMethod(
    f = "mySubset",
    signature = c(x = "myclass", subset = "ANY"),
    definition = function(x, subset){ 
       ## insert default behaviour (might be an error),
       ## a call to subset.default or whatever
    }
)

## now write an S3 method for subset that calls the S4 generic if
## x is of class myclass

subset.myClass <- function(x,subset){
  mySubset(x,subset)
}

Это сохраняет поведение подмножества только для S3, но теперь у вас есть контроль над диспетчеризацией методов на уровне S4 при условии, что x относится к классу myclass.

Вашим пользователям не нужно ценить это различие; они все еще могут звонить subset(x,class) так же, как они привыкли, когда x имеет ваш новый класс.

person JDL    schedule 19.03.2018