How can assign values for S4 slot, based on predefined lists?
B1 class created as:
mySlots <- c("myA", "c")
myTypes <- c("numeric", "character")
myVals <- c(1222, "blabla")
mySlotTypes <- setNames(as.list(myTypes), as.list(mySlots))
mySlotValues <- setNames(as.list(myVals), as.list(mySlots))
setClass("B1",
do.call("representation", mySlotTypes)
)
Manually slot can assign with:
> x <- new("B1")
> x@myA <- 2333
> x@c <- "ddd"
> str(x)
Formal class 'B1' [package ".GlobalEnv"] with 2 slots
..@ myA: num 2333
..@ c : chr "ddd"
I tried two options:
Option A
Trying to assign with prototype:
setClass("B1",
do.call("representation", mySlotTypes),
do.call("prototype", mySlotValues)
)
what gave error:
Error in makePrototypeFromClassDef(properties, ClassDef, immediate, where) : in making the prototype for class “B1” elements of the prototype failed to match the corresponding slot class: myA (class "numeric" )
Option B
Tried with initialize method without luck as well:
setMethod("initialize", signature = "B1",
definition = function (.Object) {
for(i in slotNames(.Object)) {
do.call("<-", list( str_c(".Object@", i), mySlotValues[[i]]))
}
return (.Object)
})
This solution doesn't gave error, but not initalized at all:
> x <- new("B1")
> str(x)
Formal class 'B1' [package ".GlobalEnv"] with 2 slots
..@ myA: num(0)
..@ c : chr(0)
Is there any simple solution, how can replace the manual .Object@myA <- 1222
call with loop friendly assignement?
If you look at the ?slot
help page (linked from the ?"@"
help page), it appears you can do something like this:
slot(.Object, i) <- mySlotValues[[i]]
Generally concatenating code as a string (as you've attempted with str_c(".Object@", i)
) doesn't work unless you use eval(parse(...))
, on the resulting string. This is best avoided. (In this case since you're assigning to the parsed string, you'd further need to use assign()
or include the assignment as part of the string.)
Your do.call
is a good idea and is pretty close. It would probably also work if you used the function "@<-"
instead of just <-
. Assigning to indices/items/slots have their own functions combining the accessing operator (like $
, [
, [[
, names()
or in this case @
) with the assignment. Using do.call
on the @<-
function would look like this, and would also work, but it's a bit harder to read.
do.call("@<-", list(object = ".Object", name = i, value = mySlotValues[[i]]))