I defined an S4 class with a slot i. Then I wrote a regular function that attempted to increment i. This didn't work, apparently because of the general rule that a function can't change the values of its arguments outside the function. I gather there are ways around it, but the Green book admonishes "cheating on the S evaluation model is to be avoided" (p. 190). Thinking that class methods needed to an exception to this rule, I then tried setMethod with the function I had written. However, when I called the function I got> setMethod("nextPath", "CompletePathMaker", nextPath)Creating a new generic function for 'nextPath' in '.GlobalEnv' [1] "nextPath"> nextPath(pm)Error: protect(): protection stack overflow I can change the value of the slot interactively, so the problem does not appear to be that the slots are considered off-limits. What do I need to do to update slot values? Here are some possibly relevant code fragments setClass("CompletePathMaker", representation(i="integer", timeOffset="numeric", # to avoid 0's truePaths="TruePaths") ) nextPath <- function(pm){ #pm is a CompletePathMaker pm at i <- pm at i+as.integer(1) [etc] I'm trying to make the class behave like an iterator, with i keeping track of its location. I'm sure there are more R'ish ways to go, but I'm also pretty sure I'm going to want to be able to update slots. Thanks. Ross Boylan
>>>>> "Ross" == Ross Boylan <ross at biostat.ucsf.edu> >>>>> on Fri, 03 Jun 2005 17:04:08 -0700 writes:Ross> I defined an S4 class with a slot i. Then I wrote a regular function Ross> that attempted to increment i. Ross> This didn't work, apparently because of the general rule that a function Ross> can't change the values of its arguments outside the function. I gather Ross> there are ways around it, but the Green book admonishes "cheating on the Ross> S evaluation model is to be avoided" (p. 190). Ross> Thinking that class methods needed to an exception to this rule, I then Ross> tried setMethod with the function I had written. However, when I called Ross> the function I got >> setMethod("nextPath", "CompletePathMaker", nextPath) Ross> Creating a new generic function for 'nextPath' in '.GlobalEnv' Ross> [1] "nextPath" >> nextPath(pm) Ross> Error: protect(): protection stack overflow Ross> I can change the value of the slot interactively, so the problem does Ross> not appear to be that the slots are considered off-limits. Ross> What do I need to do to update slot values? Ross> Here are some possibly relevant code fragments Ross> setClass("CompletePathMaker", Ross> representation(i="integer", Ross> timeOffset="numeric", # to avoid 0's Ross> truePaths="TruePaths") Ross> ) Ross> nextPath <- function(pm){ #pm is a CompletePathMaker Ross> pm at i <- pm at i+as.integer(1) Ross> [etc] If your nextPath function has 'pm' as its last statement it will return the updated object, and if you call it as mypm <- nextPath(mypm) you are 1) updating mypm 2) in a proper S way (i.e. no cheating). Regards, Martin Ross> I'm trying to make the class behave like an iterator, with i keeping Ross> track of its location. I'm sure there are more R'ish ways to go, but Ross> I'm also pretty sure I'm going to want to be able to update slots. Ross> Thanks. Ross> Ross Boylan
On Mon, 2005-06-06 at 14:15 -0700, Berton Gunter wrote:> I'm puzzled: > > > It looks as if instances of class objects are best thought of as > > immutable once created. > > > > what then is setReplaceMethod() for?assignment operators do the whole object replacement behind the scenes, at least conceptually, as far as I can tell. I agree: they are mutators. But outside of this special case, it seems mutation of slots is difficult (i.e., requires the assistance of the caller). By the way, the documentation on setReplaceMethod does not actually say what it does. I found out by looking at the code. Second, in my experiments I couldn't get setReplacementMethod to work: "bumpIndex<-" <- function(pm, value) { pm at i <- pm at i+as.integer(value) pm } # I get an error without the next function definition bumpIndex <- function(pm) pm at i setReplaceMethod("bumpIndex", signature=signature(pm="CompletePathMaker", value="numeric"), bumpIndex) When I try to load this, I get arguments in definition changed from (spec) to (object) arguments in definition changed from (self) to (object) arguments in definition changed from (self) to (object) Creating a new generic function for 'bumpIndex<-' in '.GlobalEnv' Error in conformMethod(signature, mnames, fnames, f) : In method for function "bumpIndex<-": formal arguments omitted in the method definition cannot be in the signature (value = "numeric") All the errors are triggered by setReplaceMethod. Can anyone help me interpret them? Or, maybe better, tell me how to debug the "compilation"?> I leave it to language "experts" to say whether S4 formal classes and > methods are wise or not in comparison to others. From my fairly ignorant > perspective, that always seems to be a matter of taste.There are actually two related issues on that score: first, whether the complex of expectation set up by talking about "objects" and "classes" are met by what R/S does, and second the wisdom of what R/S does in its own right.> > Cheers, > Bert > >-- Ross Boylan wk: (415) 502-4031 530 Parnassus Avenue (Library) rm 115-4 ross at biostat.ucsf.edu Dept of Epidemiology and Biostatistics fax: (415) 476-9856 University of California, San Francisco San Francisco, CA 94143-0840 hm: (415) 550-1062
Ross Boylan wrote:> I defined an S4 class with a slot i. Then I wrote a regular function > that attempted to increment i.[... details deleted ...]> What do I need to do to update slot values? > > Here are some possibly relevant code fragments > setClass("CompletePathMaker", > representation(i="integer", > timeOffset="numeric", # to avoid 0's > truePaths="TruePaths") > ) > nextPath <- function(pm){ #pm is a CompletePathMaker > pm at i <- pm at i+as.integer(1) > [etc] > > I'm trying to make the class behave like an iterator, with i keeping > track of its location. I'm sure there are more R'ish ways to go, but > I'm also pretty sure I'm going to want to be able to update slots.Hello Ross, I see that your question was related to S4, but I just noticed a solution based on the R.oo package so I thought I would add a solution based on the proto package too. We had similar problems several times ago and (to my surprise) found R to be an extremely flexible language even for these things. Our favorite solution is available as package(proto). It requires R 2.1, because of several subtle improvements regarding environments, which made our implementation more streamlined. Does the following example do what you intended? ##====================================================library(proto) ## 1) define an object CompletePathMaker <- proto( index = 0, bumpIndex = function(., dindex = 1) .$index <- .$index + as.integer(dindex) ) ## 2) create a child object of CompletePathMaker cpm <- CompletePathMaker$proto() ## 3) set the index component to 3 cpm$index <- 3 ## 4) iterate the index cpm$bumpIndex(2) ## print the result cpm$index ##==================================================== This approach is very compact and needs only one new function: proto. Also note how simple it is conceptually. We did not even create any classes. We just created a parent object CompletePathMaker and a child to it, cpm, and got everything else via delegation (i.e. inheritance). Hope it helps Thomas P.