modify variable within R function
Solution 1
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...
Solution 2
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
Solution 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)
}
Solution 4
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:
- The right side is looked at first. An environment for the function
abc
is set up. - A pointer is created in that environment called
x
. x
points to the same value thatg
points to.- Then
x
points to 5 - The function returns the pointer
x
g
now points to the same value thatx
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.
Alex
Updated on June 04, 2022Comments
-
Alex about 2 years
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.-
Paul Hiemstra over 12 yearsmy feeling is that the R way to do is to say g = abc() where abc returns 5. why this specific syntax?
-
-
joran over 12 yearsWith a slight modification to
abc
so that it actually returns a value, yes. -
Alex over 12 yearsyes 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.
-
Joshua Ulrich over 12 yearsThere's also the proto package.
-
Alex over 12 yearsinteresting! 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
-
Tommy over 12 years@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 thatx
andy
are now different. -
Dason almost 5 years@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.
-
Rafa over 2 yearsI 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 over 2 years... 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
-
Dason over 2 years@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.