Call by reference in R

Call by reference in R

Call by reference in R: Sometimes it is convenient to use “call by reference evaluation” inside an R function. For example, if you want to have multiple return value for your function, then either you return a list of return value and split them afterward or you can return the value via the argument.

For some reasons(I would like to know too), R do not support call by reference. The first reason come up in my mind is safety, if the function can do call by reference, it is more difficult to trace the code and debug(you have to find out which function change the value of your variables by examining the details of your function). In fact, R do “call by reference” when the value of the argument is not changed. They will make a copy of the argument only when the value is changed.  So we can expect there’s no efficiency gain (at least not a significant one) even we can do call by reference.

Pseudo call by reference

Anyway, it is always good to know how to have a “pseudo call by reference” in R (you can choose (not) to use it for whatever reason). The trick to implement call by reference is to make use of the eval.parent function in R. You can add a code to replace the argument value in the parent environment so that the function looks like implementing the call by reference evaluation strategy. Here are some examples of how to do it:

1
2
3
4
5
6
7
set<-function(x,value){
   eval.parent(substitute(x<-value))
}
valX <- 51
set(valX ,10)
valX
>[1] 10
1
2
3
4
5
6
7
addOne_1<-function(x,value){
   eval.parent(substitute(x<-x+1))
}
valX <- 51
addOne_1(valX)
valX
>[1] 52

Note that you could not change the value of x inside the function. If you change the value of x, a new object will be created. The substitute function will replace x with the new value and hence this method wont work. For example

1
2
3
4
5
6
7
addOne_2<-function(x,value){
   x<-x+1
   eval.parent(substitute(x<-x))
}
valX <- 51
addOne_2(valX)
>Error in 52 <- 52 : invalid (do_set) left-hand side to assignment

If you want to change the value of x inside the function, you have to copy x to a new object and use new object as x.  At the end of the function, you can replace the value of x with the new object at the parent environment.

1
2
3
4
5
6
7
8
9
addOne_3<-function(x,value){
   xx<-x
   xx<-xx+1
   eval.parent(substitute(x<-xx))
}
valX <- 51
addOne_3(valX)
valX
>[1] 52

Another way to do call by reference more formally is using the R.oo packages.

Another way to implement.

TszKin Julian Chan

Llamada por referencia en R

Call by reference in R: A veces es conveniente usar "evaluación de llamada por referencia" dentro de una función R. Por ejemplo, si desea tener un valor de retorno múltiple para su función, puede devolver una lista de valores de retorno y dividirlos después o puede devolver el valor mediante el argumento.

Por algunas razones (me gustaría saber también), R no admite llamadas por referencia. La primera razón que me viene a la mente es la seguridad, si la función puede llamar por referencia, es más difícil rastrear el código y depurar (debe averiguar qué función cambia el valor de sus variables examinando los detalles de su función). De hecho, R "llama por referencia" cuando el valor del argumento no cambia. Harán una copia del argumento solo cuando se cambie el valor. Por lo tanto, podemos esperar que no haya una ganancia de eficiencia (al menos no significativa), incluso podemos llamar por referencia.

pseudo llamada por referencia" en R

De todos modos, siempre es bueno saber cómo tener una "pseudo llamada por referencia" en R (puede elegir (no) usarla por cualquier razón). El truco para implementar la llamada por referencia es hacer uso de la función eval.parent en R. Puede agregar un código para reemplazar el valor del argumento en el entorno principal para que la función parezca implementar la estrategia de evaluación de llamada por referencia. Aquí hay algunos ejemplos de cómo hacerlo:

1
2
3
4
5
6
7
set<-function(x,value){
   eval.parent(substitute(x<-value))
}
valX <- 51
set(valX ,10)
valX
>[1] 10
1
2
3
4
5
6
7
addOne_1<-function(x,value){
   eval.parent(substitute(x<-x+1))
}
valX <- 51
addOne_1(valX)
valX
>[1] 52

Tenga en cuenta que no puede cambiar el valor de x dentro de la función. Si cambia el valor de x, se creará un nuevo objeto. La función de sustitución reemplazará x con el nuevo valor y, por lo tanto, este método no funcionará. Por ejemplo:

1
2
3
4
5
6
7
addOne_2<-function(x,value){
   x<-x+1
   eval.parent(substitute(x<-x))
}
valX <- 51
addOne_2(valX)
>Error in 52 <- 52 : invalid (do_set) left-hand side to assignment

Si desea cambiar el valor de x dentro de la función, debe copiar x a un nuevo objeto y usar un nuevo objeto como x. Al final de la función, puede reemplazar el valor de x con el nuevo objeto en el entorno principal.

1
2
3
4
5
6
7
8
9
addOne_3<-function(x,value){
   xx<-x
   xx<-xx+1
   eval.parent(substitute(x<-xx))
}
valX <- 51
addOne_3(valX)
valX
>[1] 52

Otra forma de hacer una llamada por referencia de manera más formal es usando los paquetes R.oo.

Otra forma de implementar.

TszKin Julian Chan

Leave a Reply