I've been using an approach that Andy Houseman showed me to create pointers and allow passing by reference in R. The basic idea is to create a class constructor and have each instantiation of the class be its own environment. One can then pass the object/environment into a function and it will be passed by reference rather than by value, because unlike other R objects, environments are not copied when passed to functions. Changes to the object in the function will change the object in the calling frame. In this way, one can operate on the object and change internal elements without having to create a copy of the object when the function is called nor pass the entire object back from the function. For large objects, this saves memory and time. The elements of the object, e.g., 'myFun', are local variables within the environment, accessed via list-like syntax, e.g., myFun$value. Note that care must be taken when assigning such objects/pointers because environments are not copied when used in assignments. You need to create an explicit copy function; assignment merely creates an additional name (i.e., pointer) referencing the existing object. These ideas are used extensively in the spectralGP library.
Here's a basic example with a constructor, newPointer(), a copy S3 method, and an S3 method for updating the referenced value, updatePointerValue():
newPointer=function(inputValue){
object=new.env(parent=globalenv())
object$value=inputValue
class(object)='pointer'
return(object)
}
copy.pointer=function(object1,object2=NULL,...){
if (is.null(object2)) {
object2 = new.env(parent = globalenv())
class(object2) = class(object)
nullFlag = TRUE
}
elements = names(object)
for (index in 1:length(elements)) {
assign(elements[index], get(elements[index], env =
object,
inherits = FALSE), env = object2)
}
if (nullFlag)
{ return(object2)
} else {
return(NULL)
}
}
updatePointerValue=function (object, ...) { # create S3
generic
UseMethod("updatePointerValue")
}
updatePointerValue.pointer=function(object,newValue){ #
create S3 method
if (!is.gp(object)) { stop(" 'object' argument must
be of class 'gp' ") }
object$value=newValue
return(NULL)
}
##### Example
myP=newPointer(7)
print(myP$value) # returns '7'
newP=copy(myP)
copyP=myP
updatePointerValue(myP,9)
print(copyP$value) # returns '9'
print(newP$value) # returns '7'
Keywords: R, pointer, pass-by-reference, object orientation, environments, classes
Last modified: 4/2/06.