russellpierce
russellpierce

Reputation: 4711

In R, how can one make a method of an S4 object that directly adjusts the values inside the slots of that object?

Is there a way to allow a method of an S4 object to directly adjust the values inside the slots of that object without copying the entire object into memory and having to re-write it to the parent environment at the end of the method? Right now I have an object that has slots where it keeps track of its own state. I call a method that advances it to the next state, but right now it seems like I have to assign() each value (or a copy of the object invoking the method) back to the parent environment. As a result, the object oriented code seems to be running a lot slower than code that simply adjusts the various state variables in a loop.

Upvotes: 4

Views: 2599

Answers (3)

Mahdi Jadaliha
Mahdi Jadaliha

Reputation: 1977

R has three object oriented (OO) systems: S3, S4 and Reference Classes (where the latter were for a while referred to as [[R5]], yet their official name is Reference Classes).

Reference Classes (or refclasses) are new in R 2.12. They fill a long standing need for mutable objects that had previously been filled by non-core packages like R.oo, proto and mutatr. While the core functionality is solid, reference classes are still under active development and some details will change. The most up-to-date documentation for Reference Classes can always be found in ?ReferenceClasses.

There are two main differences between reference classes and S3 and S4:

  • Refclass objects use message-passing OO
  • Refclass objects are mutable: the usual R copy on modify semantics do not apply.

These properties makes this object system behave much more like Java and C#. read more here:

  1. http://adv-r.had.co.nz/R5.html

  2. http://www.inside-r.org/r-doc/methods/ReferenceClasses

Upvotes: 4

Joris Meys
Joris Meys

Reputation: 108523

I asked this question on the R-list myself, and found a work-around to simulate a pass by reference, something in the style of :

eval(
  eval(
     substitute(
        expression(object@slot <<- value)
     ,env=parent.frame(1) )
  )
)

Far from the cleanest code around I'd say...

A suggestion coming from the R-help list, uses an environment to deal with these cases. EDIT : tweaked code inserted.

setClass("MyClass", representation(.cache='environment',masterlist="list"))

setMethod("initialize", "MyClass",
  function(.Object, .cache=new.env()) {
    .Object@masterlist <- list()
    callNextMethod(.Object, .cache=.cache)
  })

sv <- function(object,name,value) {} #store value

setMethod("sv",signature=c("MyClass","character","vector"),
  function(object, name, value) {
    [email protected]$masterlist[[name]] <- value
  })

rv <- function(object,name) {} #retrieve value

setMethod("rv",signature=c("MyClass","character"),
  function(object, name) {
    return([email protected]$masterlist[[name]])
  })

Upvotes: 3

Etienne Racine
Etienne Racine

Reputation: 1363

As far as I know (and if I get you correctly), you have to recopy the whole object. You can't easily pass values by reference, it is always passed "by value". So once you have modified (a copy of) your object, you need to recopy it back to your object.

John Chamber is pretty explicit about it in his book Software for Data Analysis. It's a way to avoid surprises or side effects.

I think there are some workaround using environments, but I can't help with this.

Upvotes: 1

Related Questions