Consider a recursively constructed and arbitrarily deep nested S4 object:
setClass("person", representation(name = "character", child = "ANY"), prototype(name = "", child = NA_real_))
createGeneology <- function(children){
object <- new("person", name = children[1])
if(length(children) > 1) object@child <- createGeneology(children[2:length(children)])
return(object)
}
object <- createGeneology(children = c("Arthur", "Aiden", "Adalyn", "Ava", "Aaron", "Andy"))
In a real-world situation, slots in each layer have some dependency on the layer(s) below. In this situation, it's just a static family tree.
I can directly access and modify slots by typing out the path:
differentKid <- new("person", name = "Logan")
genIV <- object@child@child@child
object@child@child@child <- differentKid
How can this be done dynamically (without typing out an arbitrary number of @child
elements?)
I can access the object dynamically by constructing a string and evaluating it with parse
, but this trick does not work for modifying the object as eval
tries to parse the result as an array:
str <- "object@child@child@child"
genIV <- eval(parse(text = str))
do.call
doesn't work:
do.call("<-", list(eval(parse(text = str)), "new('Person', name = 'Logan')"))
assign
doesn't work, get
doesn't work, so is this just bad practice, is there a better way to do this, or is there something I'm missing?
I've seen similar questions on Stack Overflow but they didn't deal with S4 objects (which are handled a bit differently than lists and arrays).
Still happy to hear if anyone has thoughts. In the meantime, I've been unable to find a way to dynamically access and modify deep recursive layers in an S4 object. Rather, the best solution was to recursively collapse the object into a list of layers.
Due to the memory overhead of collapsing layers in a class-specific as.list
operation, I've decided to go for a list of objects while enforcing relationships between consecutive layers.