next up previous
Next: Graphics and output Up: Working with objects Previous: Scope (i.e., dealing with

Pointers and passing by reference in R

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.


next up previous
Next: Graphics and output Up: Working with objects Previous: Scope (i.e., dealing with
Chris Paciorek 2006-04-02