0

I want to use multiple objects created within a function with another function:

test1 <- function(x){
  y <- x + 1
  z <- x * 2
}

test2 <- function(...){
  test1(x)
  print(u <- y * z)
}

x <- 2

test2(test1)

It throws the error Error in print(u <- y * z) : object 'y' not found.

How can I reuse all objects assigned in a function without using the global assignment <<-?

yPennylane
  • 760
  • 1
  • 9
  • 27
  • return with a `list()`, like `return(list(y=y, z=z))` at the end of the function. Assign inside the second function `ret1 <- test1(x)`, and use standard list access, example: `ret1$y` and `ret1$z`. – RLave May 13 '19 at 08:55
  • So it's only possible to access the last assigned object in a function without using the `<<-` ? – yPennylane May 13 '19 at 09:03
  • I'd avoid `<<-`, since it can cause troubles with new users. Any object assigned inside a function needs to be returned with `return()`. `<<-` assigns the object also outside the function env, which can have undesired results. – RLave May 13 '19 at 09:21
  • If there are no explicit returns from a function, the value of the last evaluated expression is returned automatically in R. Hence, from `test1` only the last evaluated `z` is returned. Also, if you wish to return multiple things, then use explicity `return`. For example, returning `list` having `y` and `z` – Om Sao May 13 '19 at 09:21
  • @Om Prakash Sao note that in `test1` also `z` is not returned, only the last unassigned element is returned if there's no `return()`. – RLave May 13 '19 at 09:29
  • @Om Prakash Sao : So how would I access the elements `y` and `z` inside the test2 function when I used return `test1 <- function(x){ return(y <- x + 1); return(z <- x * 2)}`? – yPennylane May 13 '19 at 09:36
  • @yPennylane, you can't use two return inside a function, that's why you need a `list()` or `c()`, to concatenate the results. – RLave May 13 '19 at 09:39

2 Answers2

1

I'd use a simple return() with a list() or c():

test1 <- function(x){
  y <- x + 1
  z <- x * 2 # if you don't use return these two won't leave test1

  return(list(y=y, z=z)) # equivalent without return() is list(y=y, z=z)
#or: list(y=y, z=z)
}

test2 <- function(...){
  ret1 <- test1(x)
  print(ret1$y * ret1$z)
 #or: return(ret1$y * ret1$z)
}

Note that the use of return() is not necessary, since the last object not assigned in a function is returned automatically.

The use of return() may help with readability though.

A read about return().

RLave
  • 8,144
  • 3
  • 21
  • 37
0

Your problem is about variable assignation: you are using a 'simple' assignment with the <- symbol. This mean the variable is assigned within its block, for instance y is defined within test1(). This mean you can not reuse it outside because it is not defined outside of test1(). To perfoerm this, try the <<- assignment symbol which assigns a variable in the upper environment and thus allow it to be reused outside of the block in which it is defined.

Elie Ker Arno
  • 346
  • 1
  • 11
  • This kind of use of `<<-` should be avoided. https://stackoverflow.com/questions/2628621/how-do-you-use-scoping-assignment-in-r – RLave May 13 '19 at 09:37