16

How do I modify an argument being passed to a function in R? In C++ this would be pass by reference.

g=4
abc <- function(x) {x<-5}
abc(g)

I would like g to be set to 5.

Alex
  • 19,533
  • 37
  • 126
  • 195

5 Answers5

14

There are ways as @Dason showed, but really - you shouldn't!

The whole paradigm of R is to "pass by value". @Rory just posted the normal way to handle it - just return the modified value...

Environments are typically the only objects that can be passed by reference in R.

But lately new objects called reference classes have been added to R (they use environments). They can modify their values (but in a controlled way). You might want to look into using them if you really feel the need...

Tommy
  • 39,997
  • 12
  • 90
  • 85
4

There has got to be a better way to do this but...

abc <- function(x){eval(parse(text = paste(substitute(x), "<<- 5")))}
g <- 4
abc(g)
g

gives the output

[1] 5
Dason
  • 60,663
  • 9
  • 131
  • 148
  • @joran nothing like getting called out ~8 years later to make one feel at home on SO. But yeah you're right. And I threw an upvote their way. But really I want to downvote myself and their answer and burn the whole question to the ground. – Dason Aug 14 '19 at 01:17
  • I have arrived to this answer out of desperation, and believe there might be a justified use case for this. I am using a websocket API to receive updates on stock prices, with the websocket package. The new data is received only as 1 data point (the most recent) at a time, which I then need to collate into a data frame or similar holding all data points until current time. Every time a message is received from the websocket connection, an onMessage hook is executed. The most reasonable solution I have found is to include an assignment in the onMessage hook of the form... – Rafa Mar 28 '22 at 06:40
  • ... that you mention to modify the value of the existing data frame to cbind(dataframe, new_data_row) . The reason it wouldn't be practical to be applying the standard "return the new value" paradigm is that the hook is internally handled by the websocket package code – Rafa Mar 28 '22 at 06:42
  • @Rafa I don't know what you're doing but handling any input from the web using eval just seems like asking to get hacked. – Dason Mar 28 '22 at 10:06
3

I have a solution similar to @Dason's, and I am curious if there are good reasons not to use this or if there are important pitfalls I should be aware of:

changeMe = function(x){
assign(deparse(substitute(x)), "changed", env=.GlobalEnv)
}   
John R.B. Palmer
  • 2,082
  • 3
  • 17
  • 23
2

I think that @Dason's method is the only way to do it theoretically, but practically I think R's way already does it.

For example, when you do the following:

y <- c(1,2)
x <- y

x is really just a pointer to a the value c(1,2). Similarly, when you do

abc <- function(x) {x <- 5; x}
g <- abc(g)

It is not that you are spending time copying g to the function and then copying the result back into g. I think what R does with the code

g <- abc(g)

is:

  1. The right side is looked at first. An environment for the function abc is set up.
  2. A pointer is created in that environment called x.
  3. x points to the same value that g points to.
  4. Then x points to 5
  5. The function returns the pointer x
  6. g now points to the same value that x pointed to at the time of return.

Thus, it is not that there is a whole bunch of unnecessary copying of large options.

I hope that someone can confirm/correct this.

Xu Wang
  • 10,199
  • 6
  • 44
  • 78
  • interesting! i would be curious to know if this is right. in my program that has a df that is approximately a gig, it seems that df gets copied several times as my RAM usage grows pretty large – Alex Dec 07 '11 at 19:20
  • @Alex: In this case, yes - but only since it is trivial. If you modify a part of a large vector it is typically (but not always) copied. `x <- runif(1e6); y <- x; x[4] <- 42` makes a copy so that `x` and `y` are now different. – Tommy Dec 07 '11 at 20:56
0

Am I missing something as to why you can't just do this?

g <- abc(g)
Rory
  • 59
  • 1
  • With a slight modification to `abc` so that it actually returns a value, yes. – joran Dec 07 '11 at 17:51
  • yes that would work. the point is to modify the value within teh function though without throwing around all these big objects and making copies of them. – Alex Dec 07 '11 at 17:53