2

I'm using the data.table package in R. Among other things, data.table causes tables to be passed by reference. Data.table also supports inserting or deleting columns byRef, so you can do things like this...

library('data.table')

AddSquares<-function(DT){
  DT[,x2:=(x*x)]
}

DT<-data.table(x=1:3)
AddSquares(DT)

DT
   x x2
1: 1  1
2: 2  4
3: 3  9

x2 was created in DT byRef so I didn't have to return the modified table. Easy peezy. Unfortunately, data.table doesn't support inserting or deleting rows byRef, so this following happens...

StripEvens<-function(DT){
  DT <- DT[x %% 2 != 0]
}

StripEvens(DT)

DT
   x x2
1: 1  1
2: 2  4
3: 3  9

The <- operator works by value, so it's creating a copy of DT inside the function. If I don't then return DT from then the function then it's 'destroyed' when the function call ends. If I do return DT then I can get back a table that looks the way I want, but I've done so by making a copy, which might as well be passing byVal.

So here's the question. Once DT is passed into my function byRef, how do I make R continue to work on DT byRef? Equivalently, how do I make R treat the DT inside the function as a reference to the same object that DT outside the function references? Is this even possible?

Adam Hoelscher
  • 1,804
  • 2
  • 17
  • 33
  • more or less duplicate of http://stackoverflow.com/questions/2603184/r-pass-by-reference – eddi Apr 02 '15 at 17:52

1 Answers1

3

This will kind of do it, in the same type of way that names(x) <- letters does it. That is, it looks like it is by reference, but it isn't really. If you care about the semantics as opposed to whether a copy of the object gets made or not, then you can do something like this:

library(data.table)
DT1 <- data.table(x=1:3)

StripEvens<-function(DT) {
  x <- substitute(DT)
  if(is.name(x)) {
    DT.ext <- get(as.character(x), parent.frame(), inherits=FALSE)
    if(identical(DT, DT.ext)) {
      assign(as.character(x), DT[x %% 2 != 0], envir=parent.frame())
  } } 
  return(invisible(NULL))
}

StripEvens(DT1)
DT1

Produces:

   x
1: 1
2: 3

This is not fully robust (i.e. breaks if the object is not actually in the parent frame, etc.), but can be made robust with a little work. The bigger issue is that the object isn't actually modified by reference, but rather, copied, modified, and replaced. As others have pointed out, actual by reference modifications aren't possible, unless you write your functions in C.

BrodieG
  • 51,669
  • 9
  • 93
  • 146