简体   繁体   中英

R: Changing an S4 object from within an S4 method

I have an S4 object that represents a recursive tree structure containing some data and other objects of the same class. I also have a recursive function to modify two slots in each node in the tree. The function (call it "propagate()") does its thing properly when I do this:

> obj <- treeObj(4, 5)
> slotNames(obj)
[1] "x" "y" "listOfOtherTreeObjs"
> obj <- propagate(obj, 1, 4)  

I can write a function like this that takes an argument and populates the tree with that data, no problem.

What I want, though, is to be able to call propagate() from within a method of the root object:

setMethod("transform", signature="treeObj",
    definition=function(object, i, j) {
         object@x <- i;  object@y <- j;
         object <- propagate(object, i, j);
         ... (do some other stuff in the tree)
    })

In this method, propagate() seems to function as it should, but its result does not seem to be assigned to the parent object in a way that is detectable within the transform() method definition. My questions:

  1. I imagine this is to do with the call-by-value nature of R and that I cannot affect the value of the object that was used to invoke the transform function. Is that correct or am I just being stupid and this should work?

  2. Is there any kind of R magic to get around this? Some way to invoke the 'assign()' function to force the new definition of object to replace the current one? Or something?

  3. Is there a more R-ish way to build my recursive object to support this kind of thing?

Thanks in advance.

There are two things you need to do to make this work:

1) presumably, the recursion doesn't go on for ever ie at some point an object won't contain a link to another object because it is at the bottom of the tree. So you need the possibility that the list of other tree objs is NULL. You do this with a class union:

setClassUnion("listOfOtherTreeObjsOrNULL",c("listOfOtherTreeObjs","NULL"))

and then the correct class to use in the third slot of your object is this new class union.

2) when you are defining the method for transform it needs to look something like this:

function(object,i,j){
  ## do whatever you want with i and j
  if(is.null(object@listOfOtherTreeObjs)) return(object)
  else{
    object@listOfOTherTreeObjs <- lapply(object@listOfOtherTreeObjs,propagate)
    return(object)
  }
}

The reason your changes didn't appear to take any effect is that you were not return ing anything from your function, so you were only modifying copies of your objects which weren't being saved anywhere.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM