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

Note, this material is essentially superseded by R's ReferenceClass functionality. See help(ReferenceClasses) in R.

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.

You may also want to look into the R.oo package.

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=function (object, ...) { # create S3 generic 
UseMethod("copy")  
}  
copy.pointer=function(object1,object2=NULL,...){ 
if (is.null(object2)) {  
object2 = new.env(parent = globalenv())  
class(object2) = class(object1) 
nullFlag = TRUE  
}  
elements = names(object1)  
for (index in 1:length(elements)) {  
assign(elements[index], get(elements[index], env = object1,  
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(object, "pointer")) { stop(" 'object' argument must be of class 'pointer' .") }  
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, call by reference, pass by reference, object orientation, environments, classes

Last modified: 3/24/13.


next up previous
Next: Graphics and output Up: Working with objects Previous: Scope (i.e., dealing with
Chris Paciorek 2012-01-21