Return Values

The return value of a function can be any R object. Although the return value is often a list, it could even be another function.

You can transmit a value back to the caller by explicitly calling return(). Without this call, the value of the last executed statement will be returned by default. For instance, consider the oddcount() example from Chapter 1:

> oddcount
function(x)  {
   k <- 0  # assign 0 to k
   for (n in x)  {
      if (n %% 2 == 1) k <- k+1  # %% is the modulo operator
   }
   return(k)
}

This function returns the count of odd numbers in the argument. We could slightly simplify the code by eliminating the call to return(). To do this, we evaluate the expression to be returned, k, as our last statement in the code:

oddcount <- function(x) {
   k <- 0
   pagebreak
   for (n in x) {
      if (n %% 2 == 1) k <- k+1
   }
   k
}

On the other hand, consider this code:

oddcount <- function(x) {
   k <- 0
   for (n in x) {
      if (n %% 2 == 1) k <- k+1
   }
}

It wouldn’t work, for a rather subtle reason: The last executed statement here is the call to for(), which returns the value NULL (and does so, in R parlance, invisibly, meaning that it is discarded if not stored by assignment). Thus, there would be no return value at all.

The prevailing R idiom is to avoid explicit calls to return(). One of the reasons cited for this approach is that calling that function lengthens execution time. However, unless the function is very short, the time saved is negligible, so this might not be the most compelling reason to refrain from using return(). But it usually isn’t needed nonetheless.

Consider our second example from the preceding section:

oddcount <- function(x) {
   k <- 0
   for (n in x) {
      if (n %% 2 == 1) k <- k+1
   }
   k
}

Here, we simply ended with a statement listing the expression to be returned—in this case, k. A call to return() wasn’t necessary. Code in this book usually does include a call to return(), for clarity for beginners, but it is customary to omit it.

Good software design, however, should be mean that you can glance through a function’s code and immediately spot the various points at which control is returned to the caller. The easiest way to accomplish this is to use an explicit return() call in all lines in the middle of the code that cause a return. (You can still omit a return() call at the end of the function if you wish.)

Since the return value can be any R object, you can return complex objects. Here is an example of a function being returned:

> g
function() {
   t <- function(x) return(x^2)
   return(t)
}
> g()
function(x) return(x^2)
<environment: 0x8aafbc0>

If your function has multiple return values, place them in a list or other container.