1

I am trying to change a variable in a function but even tho the function is producing the right values, when I go to use them in the next sections, R is still using the initial values.

I created a function to update my variables NetN and NetC:

Reproduction=function(NetN,NetC,cnrep=20){
     if(NetC/NetN<=cnrep) {
    DeltaC=NetC*p;
    DeltaN=DeltaC/cnrep;
    Crep=Crep+DeltaC;
    Nrep=Nrep+DeltaN;
    Brep=(Nrep*14+Crep*12)*2/1e6;
    NetN=NetN-DeltaN;  #/* Update N, C values */
    NetC=NetC*(1-p)
    print ("'Using C to allocate'")
    }
    
    else {
    print("Using N to allocate");
    DeltaN=NetN*p;
    DeltaC=DeltaN*cnrep;
    Nrep=Nrep+DeltaN;
    Crep=Crep+DeltaC;
    Brep=(Nrep*14+Crep*12)*2/1e6;
    NetN=NetN*(1-p);
    NetC=NetC-DeltaC;
    }   } return(c(NetC=NetC,NetN=NetN,NewB=NewB,Crep=Crep,Nrep=Nrep,Brep=Brep))}

When I use my function by say doing:

 Reproduction(NetN=1.07149,NetC=0.0922349,cnrep=20)

I get the desired result printed out which includes:

NetC=7.378792e-02

However, when I go to use NetC in the next section of my code, R is still using NetC=0.0922349.

Can I make R update NetC without having to define a new variable?

  • 1
    In R, in general, functions shouldn't change things outside of the function. They should return values (which yours does nicely), and if you want to keep those values, they get assigned. They way your function is built now, something like `updates <- Reproduction(...)` and then `NetC <- updates["NetC"]` would work. – Gregor Thomas Jun 25 '20 at 15:23

1 Answers1

1

In R, in general, functions shouldn't change things outside of the function. It's possible to do so using <<- or assign(), but this generally makes your function inflexible and very surprising.

Instead, functions should return values (which yours does nicely), and if you want to keep those values, you explicitly use <- or = to assign them to objects outside of the function. They way your function is built now, you can do that like this:

updates = Reproduction(NetN = 1.07149, NetC = 0.0922349, cnrep = 20)
NetC = updates["NetC"]

This way, you (a) still have all the other results of the function stored in updates, (b) if you wanted to run Reproduction() with a different set of inputs and compare the results, you can do that. (If NetC updated automatically, you could never see two different values), (c) You can potentially change variable names and still use the same function, (d) You can run the function to experiment/see what happens without saving/updating the values.

If you generally want to keep NetN, NetC, and cnrep in sync, I would recommend keeping them together in a named vector or list, and rewriting your function to take that list as input and return that list as output. Something like this:

params = list(NetN = 1.07149, NetC = 0.0922349, cnrep = 20)

Reproduction=function(param_list){
    NetN = param_list$NetN
    NetC = param_list$NetC
    cnrep = param_list$cnrep
    if(NetC/NetN <= cnrep) {
      DeltaC=NetC*p;
      DeltaN=DeltaC/cnrep;
      Crep=Crep+DeltaC;
      Nrep=Nrep+DeltaN;
      Brep=(Nrep*14+Crep*12)*2/1e6;
      NetN=NetN-DeltaN;  #/* Update N, C values */
      NetC=NetC*(1-p)
      print ("'Using C to allocate'")
    }
    
    else {
      print("Using N to allocate");
      DeltaN=NetN*p;
      DeltaC=DeltaN*cnrep;
      Nrep=Nrep+DeltaN;
      Crep=Crep+DeltaC;
      Brep=(Nrep*14+Crep*12)*2/1e6;
      NetN=NetN*(1-p);
      NetC=NetC-DeltaC;
    }   
  ## Removed extra } and ) ??
  return(list(NetC=NetC, NetN=NetN, NewB=NewB, Crep=Crep, Nrep=Nrep, Brep=Brep))
}

This way, you can use the single line params <- Reproduction(params) to update everything in your list. You can access individual items in the list with either params$Netc or params[["NetC"]].

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294