Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement subset replacement for S4 methods

Tags:

r

s4

I'm writing an S4 class in which the internal data is stored in a database and the class is mostly a gatekeeper for accessing and modifying information in the database. The class would have methods such as getInfoA and getInfoA<- for extracting and setting certain information.

My question pertains to the following case:

myObject <- new('myClass', db = 'path/to/database')
getInfoA(myObject)[1:5] <- letters[1:5]

Here the setter is subsetted before the assignment. Normally this is resolved automatically when the data is stored in standard R structures, but how to deal with this gracefully when the data are stored elsewhere? There is a [<- primitive within R, but it is unclear to me how the dispatching goes and where and how to intercept it...

like image 639
ThomasP85 Avatar asked May 04 '15 11:05

ThomasP85


1 Answers

Sadly I have no good explanation for it but it is working out of the box. Maybe an R expert could clarify this.

The main reason could be that R never replaces anything but creates a new copy of the object (with some exceptions like the primitive operators, e.g. [[<- that could replace in place under some conditions).

myClass <- setClass("myClass", slots=c(letters="character"))

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

setMethod("getLetters", "myClass", function(x) {
  x@letters
})

setReplaceMethod("getLetters", c("myClass", "character"), function(x, value) {
  message("value: ", paste0(value, collapse=", "))
  x@letters <- value
  x
})

a <- myClass(letters=LETTERS[1:10])
tracemem(a)
# [1] "<0x3716b40>"
getLetters(a)
#  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J"
getLetters(a)[1:5] <- letters[1:5]
# tracemem[0x3716b40 -> 0x39439c8]:
# tracemem[0x39439c8 -> 0x3293f70]:
# value: a, b, c, d, e, F, G, H, I, J
# tracemem[0x3293f70 -> 0x34aae60]: getLetters<- getLetters<-

So what basically seems to happen when you call getLetters(a)[1:5] <- letters[1:5] is the following:

value <- getLetters(a)
value <- c(letters[1:5], value[6:10])
a <- `getLetters<-`(a, value=value)
like image 92
sgibb Avatar answered Sep 27 '22 22:09

sgibb