¿Se puede pasar por referencia en R?

¿Puedes pasar por referencia con “R”? por ejemplo, en el siguiente código:

setClass("MyClass", representation( name="character" )) instance1 <-new("MyClass",name="Hello1") instance2 <-new("MyClass",name="Hello2") array = c(instance1,instance2) instance1 array instance1@name="World!" instance1 array 

la salida es

 > instance1 An object of class “MyClass” Slot "name": [1] "World!" > array [[1]] An object of class “MyClass” Slot "name": [1] "Hello1" [[2]] An object of class “MyClass” Slot "name": [1] "Hello2" 

pero desearía que fuera

 > instance1 An object of class “MyClass” Slot "name": [1] "World!" > array [[1]] An object of class “MyClass” Slot "name": [1] "World!" [[2]] An object of class “MyClass” Slot "name": [1] "Hello2" 

Es posible ?

No

Los objetos en las declaraciones de asignación son inmutables. R copiará el objeto no solo la referencia.

 > v = matrix(1:12, nrow=4) > v [,1] [,2] [,3] [1,] 1 5 9 [2,] 2 6 10 [3,] 3 7 11 [4,] 4 8 12 > v1 = v > v1[,1] # fetch the first column [1] 1 2 3 4 

( condición : la statement anterior es verdadera para las primitivas R, p. ej., vectores, matrices), y también para las funciones ; No puedo decir con certeza si es cierto para todos los objetos R, solo la mayoría de ellos, así como la gran mayoría de los que se usan con más frecuencia).

Si no te gusta este comportamiento, puedes optar por no participar con la ayuda de un Paquete R. Por ejemplo, hay un paquete R llamado R.oo que le permite imitar el comportamiento de referencia por paso; R.oo está disponible en CRAN .

Tenga en cuenta que si espera usar pass-by-reference simplemente para evitar las implicaciones de rendimiento de copiar un objeto que no está modificado (como es común en otros lenguajes con referencias constantes), R lo hace automáticamente:

 n < - 10^7 bigdf <- data.frame( x=runif(n), y=rnorm(n), z=rt(n,5) ) myfunc <- function(dat) invisible(with( dat, x^2+mean(y)+sqrt(exp(z)) )) myfunc2 <- function(dat) { x <- with( dat, x^2+mean(y)+sqrt(exp(z)) ) invisible(x) } myfunc3 <- function(dat) { dat[1,1] <- 0 invisible( with( dat, x^2+mean(y)+sqrt(exp(z)) ) ) } tracemem(bigdf) > myfunc(bigdf) > # nothing copied > myfunc2(bigdf) > # nothing copied! > myfunc3(bigdf) tracemem[0x6e430228 -> 0x6b75fca0]: myfunc3 tracemem[0x6b75fca0 -> 0x6e4306f0]: [< -.data.frame [<- myfunc3 tracemem[0x6e4306f0 -> 0x6e4304f8]: [< -.data.frame [<- myfunc3 > > library(microbenchmark) > microbenchmark(myfunc(bigdf), myfunc2(bigdf), myfunc3(bigdf), times=5) Unit: milliseconds expr min lq median uq max 1 myfunc2(bigdf) 617.8176 641.7673 644.3764 683.6099 698.1078 2 myfunc3(bigdf) 1052.1128 1134.0822 1196.2832 1202.5492 1206.5925 3 myfunc(bigdf) 598.9407 622.9457 627.9598 642.2727 654.8786 

Como varios han señalado anteriormente, esto se puede hacer mediante el uso de objetos del environment de clase. Existe un enfoque formal basado en el uso del environment s. Se llama clases de referencia y te facilita las cosas. Marque ?setRefClass para la página principal de ayuda de entrada. También describe cómo usar métodos formales con clases de referencia.

Ejemplo

 setRefClass("MyClass", fields=list( name="character" ) ) instance1 < - new("MyClass",name="Hello1") instance2 <- new("MyClass",name="Hello2") array = c(instance1,instance2) instance1$name <- "World!" 

Salida

 > instance1 Reference class object of class "MyClass" Field "name": [1] "World!" > array [[1]] Reference class object of class "MyClass" Field "name": [1] "World!" [[2]] Reference class object of class "MyClass" Field "name": [1] "Hello2" 

Pass-by-reference es posible para el environment s. Para usarlos, básicamente cada vez que creas un objeto necesitarías crear también un espacio de ambiente. Pero creo que es engorroso. Eche un vistazo a Pase por referencia para S4. y Punteros y pasar por referencia en R

R tiene ahora una biblioteca que le permite hacer OOP usando referencias. Vea las clases de referencia que forman parte del paquete de métodos.

En realidad, el paquete de R.oo emula el comportamiento de pasar por referencia mediante el uso de entornos.

Como otros han declarado, no es posible para las clases S4. Pero R ahora ofrece la posibilidad de una biblioteca R6 , llamada clases de referencia . Ver documentación oficial

Además de las otras respuestas aquí que realmente pasan su objeto por referencia (objetos de environment y clases de referencia), si está interesado puramente en llamar por referencia para la conveniencia sintáctica (es decir, no le importa que sus datos se copien en el interior), podrías emular eso asignando el valor final a la variable externa mientras regresas:

 byRef < - function(..., envir=parent.frame(), inherits=TRUE) { cl <- match.call(expand.dots = TRUE) cl[c(1, match(c("envir", "inherits"), names(cl), 0L))] <- NULL for (x in as.list(cl)) { s <- substitute(x) sx <- do.call(substitute, list(s), envir=envir) dx <- deparse(sx) expr <- substitute(assign(dx, s, envir=parent.frame(), inherits=inherits)) do.call(on.exit, list(expr, add=TRUE), envir=envir) } } 

Entonces podemos declarar argumentos de "llamada por referencia":

 f < - function(z1, z2, z3) { byRef(z1, z3) z1 <- z1 + 1 z2 <- z2 + 2 z3 <- z3 + 3 c(z1, z2, z3) } x1 <- 10 x2 <- 20 x3 <- 30 # Values inside: print(f(x1, x2, x3)) # [1] 11 22 33 # Values outside: print(c(x1, x2, x3)) # [1] 11 20 33 

Tenga en cuenta que si accede a las variables "por referencia" por sus nombres externos ( x1 , x3 ) en cualquier lugar dentro de la función, obtendrá sus valores aún no modificados desde el exterior. Además, esta implementación solo maneja nombres de variables simples como argumentos, por lo que los argumentos indexados como f(x[1], ...) no funcionarán (aunque probablemente podría implementar eso con un poco más de manipulación de expresiones para eludir la assign limitada )

Además de las otras sugerencias, también puede escribir funciones C / C ++ tomando sus argumentos por referencia y trabajando en el lugar , y llamarlos directamente en R gracias a Rcpp (entre otros). Ver en particular esta respuesta .