modify variable within R function

17,241

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:

  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.

Share:
17,241
Alex
Author by

Alex

Updated on June 04, 2022

Comments

  • Alex
    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
      Paul Hiemstra over 12 years
      my feeling is that the R way to do is to say g = abc() where abc returns 5. why this specific syntax?
  • joran
    joran over 12 years
    With a slight modification to abc so that it actually returns a value, yes.
  • Alex
    Alex over 12 years
    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.
  • Joshua Ulrich
    Joshua Ulrich over 12 years
    There's also the proto package.
  • Alex
    Alex over 12 years
    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
  • Tommy
    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 that x and y are now different.
  • Dason
    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
    Rafa over 2 years
    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
    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
    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.