Re: [R] S4 pass-by-value work-around?

From: Martin Morgan <mtmorgan_at_fhcrc.org>
Date: Thu, 19 Jun 2008 10:00:21 -0700

Hi again Jeff...

Jeffrey Spies <jspies2008_at_gmail.com> writes:

> Thanks for the response, Martin. While the solutions offered update the
> object appropriately, we wouldn't get the desired return value (a string
> followed by the counter, "unique_1") when the methods are called. Do you
> know a way of dealing with this?

I don't have a solution for you, other than calling a method to increment the counter and a second to retrieve the current name.

Here's another unsatisfactory solution...

setClass("Stateful",

         representation=representation(
           state="environment"))

setMethod("initialize", "Stateful",
          function(.Object, ..., state=new.env(parent=emptyenv())) {
              state[["count"]] <- 0
              callNextMethod(.Object, ..., state=state)
          })

setGeneric("state", function(x) standardGeneric("state"))

setMethod("state", "Stateful", function(x) x_at_state)

setGeneric("uname", function(x, ...) standardGeneric("uname"))

setMethod("uname", "Stateful", function(x, ...) {

    state <- state(x)
    assign("count", state[["count"]] + 1, state)     paste("unique", state[["count"]], sep="_") })

> s <- new("Stateful")
> uname(s)

[1] "unique_1"
> uname(s)

[1] "unique_2"

... and the reason why this will be surprising to users

> s <- t <- new("Stateful")
> uname(s)

[1] "unique_1"
> uname(s)

[1] "unique_2"
> uname(t) # hey, this is the first time I referenced t!
[1] "unique_3"

I guess this points to maybe some subtle issues with what you're trying to do, arising from a tension between pass-by-value and pass-by-reference (or to my own fuzzy-headed thinking). For instance, supppose you've implemented your 'uniqueName' function to update the object but return the unique name, and you've done it without using an environment like above, so that each instance of MyMatrix has its own counter. Say you have an instance x of 'MyMatrix' in the global environment. You pass it to a function. R's pass-by-value means it gets copied to a local variable in the function, say x1. The function queries 'uniqueName', modifying x1. But x in the global environment is unchanged. So the next time this function is invoked, it gets the same 'unique' name. Is this what you were expecting?

These are just my two cents, of course, maybe others have different ideas.

Martin

> Jeff.
>
>
> Martin Morgan wrote:
>>
>> Hi Jeff --
>>
>> two different scenarios are to overwrite the current object, along the
>> lines of
>>
>> y <- uniquify(y)
>>
>> where uniquify is a method like createUniqueName but returns the
>> (modified) instance rather than unique name
>>
>> setMethod('uniquify', 'MyMatrix', function(x) {
>> x_at_uniqueCount <- # something unique
>> x
>> })
>>
>> The second is a replacement method, along the lines of
>>
>> setGeneric("uniqueCount<-",
>> function(x, ..., value) standardGeneric("uniqueCount<-"))
>>
>> setReplaceMethod("uniqueCount",
>> signature=c(x="MyMatrix", value="numeric"),
>> function(x, ..., value) {
>> x_at_uniqueCount <- value
>> x
>> })
>>
>> uniqueCount(x) <- uniqueCount(x) + 1
>> x # now modified
>>
>> This is untested psuedo-code, so I hope it's right enough to get you
>> going.
>>
>> Martin
>>
>> Jeffrey Spies <jspies2008_at_gmail.com> writes:
>>
>>> Howdy all,
>>>
>>> I have a problem that I'd like some advice/help in solving---it has to do
>>> with R's pass-by-value system. I understand the issue, but am wondering
>>> if
>>> anyone has found a working solution in dealing with it for cases when one
>>> wants to modify an object inside of a method, specifically when working
>>> with
>>> S4. I'm aware that R.oo is able to deal with this using S3, but I'd
>>> really
>>> rather stick to S4.
>>>
>>> The basics of what I would like to do are coded below:
>>>
>>> setClass("MyMatrix",
>>> representation(
>>> parameters="matrix",
>>> uniqueCount="numeric"
>>> ),
>>> prototype(
>>> parameters=matrix(numeric(0),0,0),
>>> uniqueCount=1
>>> )
>>> )
>>>
>>> setGeneric("createUniqueName", function(object)
>>> standardGeneric("createUniqueName"))
>>>
>>> setMethod("createUniqueName", "MyMatrix", function(object){
>>> retval <- paste("unique_", object_at_uniqueCount, sep="")
>>> object_at_uniqueCount <- object_at_uniqueCount + 1
>>> return(retval)
>>> })
>>>
>>> x <- new("MyMatrix", parameters=matrix(0, 2, 2))
>>> createUniqueName(x) # returns "unique_1"
>>> x # x_at_uniqueCount is still 1
>>>
>>> I understand why this is happening, but am wondering how people in the
>>> community have dealt with it, specifically when using S4. Any advice
>>> would
>>> be appreciated. Also, I am aware that this is somewhat of a silly
>>> example,
>>> but it should allow you to see what I'm trying to accomplish.
>>>
>>> Thank you,
>>>
>>> Jeff.
>>>
>>
>
> --
> View this message in context: http://www.nabble.com/S4-pass-by-value-work-around--tp17997553p18012246.html
> Sent from the R help mailing list archive at Nabble.com.
>
> ______________________________________________
> R-help_at_r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.

-- 
Martin Morgan
Computational Biology / Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109

Location: Arnold Building M2 B169
Phone: (206) 667-2793

______________________________________________
R-help_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Received on Thu 19 Jun 2008 - 18:39:58 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Thu 19 Jun 2008 - 19:30:46 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-help. Please read the posting guide before posting to the list.

list of date sections of archive