Класс S4: обновить слот в другом методе, не возвращая объект (R) - PullRequest
0 голосов
/ 22 мая 2018

Для пакета R, над которым я работаю (который создает класс S4), я хотел бы отложить загрузку некоторых данных до тех пор, пока пользователь фактически не запросит их (потому что это может или не требуется, и загрузка занимает немного времени),Это потребовало бы от меня установки значения слота в его методе getter (aka accessor), если он ранее не был загружен.Но я не могу получить новое значение, чтобы "придерживаться".Вот MRE :

setClass("A", representation(value = "numeric"))

setGeneric("value<-", function(x, value) standardGeneric("value<-"))
setGeneric("value", function(x) standardGeneric("value"))

setMethod("value<-", signature("A", "numeric"),
          function(x, value) 
          {
            x@value = value
            x
          })    

setMethod("value", signature(x = "A"),
          function(x) 
          {
            if(!length(x@value))
              value(x) <- 20
            x@value
          })    

. Это дает следующий результат:

> a <- new("A")
> value(a)
[1] 20
> a
An object of class "A"
Slot "value":
numeric(0)

Таким образом, функция value () возвращает желаемое новое значение (20),но это значение фактически не обновляется в объекте.Выполнение x@value <- value вместо value(x) <- 20 в геттере также не удалось.

Кажется, проблема в том, что я не возвращаю обновленный объект в моем геттере (как это делает мой сеттер), но у меня есть что-то еще, чтобы вернуть в моем геттере (значение).

Какой правильный способ сделать это ™?

Спасибо!

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

После дальнейшего изучения S4 pass-by-valueСемантика, я пришел к выводу, что это просто не возможно ™.Если слот обновлен, объект должен быть возвращен, и вы не можете вернуть что-то еще.Может ли кто-нибудь подтвердить, что мой вывод верен?

1 Ответ

0 голосов
/ 23 мая 2018

В комментарии @Alexis упоминаются классы R6.В то время как меня просили к классам S4 для моего текущего проекта (нацеленного на BioConductor), следующее предложение из документов R6 ReferenceClasses привлекло мое внимание: «Справочные классы реализованы как классы S4 с частью данных типа« environment ». '

Так что, если я действительно хочу, чтобы изменяемые элементы при использовании классов S4, я мог эмулировать R6 следующим образом:

setClass("A", representation(inMutable = "ANY", 
                             .env = "environment"))

A = function(inMutable = NULL, mutable = NULL) {
  x <- new("A", 
           inMutable = inMutable,
           .env = new.env())
  x@.env$mutable  = mutable
  x@inMutable <- inMutable
  x
}

setGeneric("inMutable<-", function(x, value) standardGeneric("inMutable<-"))
setGeneric("inMutable", function(x) standardGeneric("inMutable"))
setGeneric("mutable<-", function(x, value) standardGeneric("mutable<-"))
setGeneric("mutable", function(x) standardGeneric("mutable"))

#setter
setMethod("inMutable<-", signature("A", "numeric"),
          function(x, value) 
          {
            x@inMutable <- value
            x
          })    

#getter
setMethod("inMutable", signature("A"),
          function(x) 
          {
            if (!length(x@inMutable))
              message("Hmmm, you haven't initialized a value for 'inMutable'.",
                      " I'm afraid I can't do anything about that now.")
            x@inMutable
          })    

#setter
setMethod("mutable<-", signature("A", "numeric"),
          function(x, value) 
          {
            x@.env$mutable <- value
            x
          })    

#getter (mutable!)
setMethod("mutable", signature("A"),
          function(x) 
          {
            if (!length(x@.env$mutable)) {
              message("Ah. You haven't initialized a value for 'mutable'. ",
                      "Lucky for you I can initialize it for you now.")
              x@.env$mutable = 12
            }
            x@.env$mutable
          })    

Тогда я могу сделать это:

> a <- A()
> mutable(a)
Ah. You haven't initialized a value for 'mutable'. 
Lucky for you I can initialize it for you now.
[1] 12
> mutable(a)
[1] 12
>
> inMutable(a)
Hmmm, you haven't initialized a value for 'inMutable'. 
I'm afraid I can't do anything about that now.
NULL
> inMutable(a) <- 18
> inMutable(a)
[1] 18
> 

Очевидно, ссылкаКлассы и R6 обеспечивают гораздо более богатое и надежное решение, но в крайнем случае это кажется жизнеспособным вариантом S4.Конечно, я не проверил это полностью в дикой природе, чтобы увидеть, где оно может сломаться.

...