Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: preventing copies when passing a variable into a function

Tags:

r

Hadley's new pryr package that shows the address of a variable is really great for profiling. I have found that whenever a variable is passed into a function, no matter what that function does, a copy of that variable is created. Furthermore, if the body of the function passes the variable into another function, another copy is generated. Here is a clear example

n = 100000
p = 100

bar = function(X) {
  print(pryr::address(X))
}

foo = function(X) {
  print(pryr::address(X))
  bar(X)
}

X = matrix(rnorm(n*p), n, p)
print(pryr::address(X))
foo(X)

Which generates

> X = matrix(rnorm(n*p), n, p)
> print(pryr::address(X))
[1] "0x7f5f6ce0f010"
> foo(X)
[1] "0x92f6d70"
[1] "0x92f3650"

The address changes each time, despite the functions not doing anything. I'm confused by this behavior because I've heard R described as copy on write - so variables can be passed around but copies are only generated when a function wants to write into that variable. What is going on in these function calls?

For best R development is it better to not write multiple small functions, rather keep the content all in one function? I have also found some discussion on Reference Classes, but I see very little R developers using this. Is there another efficient way to pass the variable that I am missing?

like image 297
JCWong Avatar asked Jan 31 '26 10:01

JCWong


1 Answers

I'm not entirely certain, but address may point to the memory address of the pointer to the object. Take the following example.

library(pryr)
n <- 100000
p <- 500
X <- matrix(rep(1,n*p), n, p)
l <- list()
for(i in 1:10000) l[[i]] <- X

At this point, if each element of l was a copy of X, the size of l would be ~3.5Tb. Obviously this is not the case as your computer would have started smoking. And yet the addresses are different.

sapply(l[1:10], function(x) address(x))
# [1] "0x1062c14e0" "0x1062c0f10" "0x1062bebc8" "0x10641e790" "0x10641dc28" "0x10641c640" "0x10641a800" "0x1064199c0"
# [9] "0x106417380" "0x106411d40"
like image 56
Ian Fellows Avatar answered Feb 03 '26 00:02

Ian Fellows