tags:

views:

89

answers:

2

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.

+1  A: 

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.

Etiennebr
It sounds like you understand my question correctly. I understand the motive and in many contexts it makes sense, but being safe here (the application: http://stats.stackexchange.com/questions/1286/how-can-i-obtain-some-of-all-possible-combinations-in-r) is costing me a lot in terms of speed, which is why I was looking for another approach.
drknexus
Have you taken a look at Rprof() to make sure the critical point is really where you think ? Or maybe you could try to use ff() to allow bigger matrices (reusing combn() code)
Etiennebr
I'm not sure how to use Rprof() effectively is there a guide somewhere?
drknexus
Right now when I try to use Rprof my code dies with the error message "Error in .getClassFromCache(Class, where) : caught access violation - continue with care".
drknexus
Maybe http://rwiki.sciviews.org/doku.php?id=tips:misc:profiling could help ?
Etiennebr
+1  A: 

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]])
  })
Joris Meys
Tweaked so it works.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 valuesetMethod("sv",signature=c("MyClass","character","vector"),function(object, name, value) { [email protected]$masterlist[[name]] <- value})rv <- function(object,name) {} #retrieve valuesetMethod("rv",signature=c("MyClass","character"),function(object, name) { return([email protected]$masterlist[[name]])})
drknexus
The code as written doesn't actually store a value to a variable defined by "name" in the call, it just stores it blindly in a variable called name. By putting a list in the environment we can then restore values by name, although stored data structures may be mangled and need to be recast when returning to regular use.
drknexus
I'm not completely following your code. You make a masterlist as a slot in the object, and then again in the .cache environment. Isn't that a bit overshoot? The one as a slot in the object doesn't serve a purpose. You can change vars there using the eval-construct I mentioned, but that's hardly to be called good programming.
Joris Meys