Skip to content
Prev 147622 / 398500 Next

S4 pass-by-value work-around?

Hi again Jeff...

Jeffrey Spies <jspies2008 at gmail.com> writes:
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="_")
})
[1] "unique_1"
[1] "unique_2"

... and the reason why this will be surprising to users
[1] "unique_1"
[1] "unique_2"
[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