15

I was helping a friend of mine with some of his code. I didn't know how to explain the strange behavior, but I could tell him that his functions weren't explicitly returning anything. Here is a minimum reproducible example:

derp <- function(arg){
  arg <- arg+3
}

data <- derp(500)
data
#[1] 503
derp(500)
#nothing outputs
class(derp(500))
#[1] "numeric"

Is there a name for this that I can google? Why is this happening? Why isn't arg being destroyed after the call to derp() finishes?

Taylor
  • 1,797
  • 4
  • 26
  • 51
  • Try `z <- derp(500); z` or `(derp(500))`. Also, see what happens if you don't assign `arg + 3` within your function's source and then use the function. – jbaums Feb 04 '14 at 01:03
  • Without an `arg` at the end of the function, you're not printing anything. Try `(derp(500))`. – Maiasaura Feb 04 '14 at 01:03

5 Answers5

16

You need to understand the difference between a function returning a value, and printing that value. By default, a function returns the value of the last expression evaluated, which in this case is the assignment

arg <- arg + 3

(Note that in R, an assignment is an expression that returns a value, in this case the value assigned.) This is why data <- derp(500) results in data containing 503.

However, the returned value is not printed to the screen by default, unless you isolate the function's final expression on its own line. This is one of those quirks in R. So if you want to see the value:

derp <- function(arg)
{
    arg <- arg + 3
    arg
}

or just

derp <- function(arg)
arg + 3
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • 7
    I don't agree with your statement "the returned value is not printed to the screen by default". It IS printed by default. The issue is that assignment sets the visibility to FALSE so that it doesn't display. It's the same reason why when you do `a <- 3` you don't see '3' get printed as well. Check out `withVisible(3)` compared to `withVisible(a <- 3)` – Dason Feb 04 '14 at 02:03
  • 4
    @Dason or even `a <- 3` vs `(a <- 3)` – hadley Feb 04 '14 at 02:21
  • Okay, good explanation. I guess it's more redundant than strange. It seems to just be chaining assignments a <- (b <- 3) – Taylor Feb 04 '14 at 04:39
  • 2
    @Dason ... "unless you isolate the function's final expression on its own line" – Hong Ooi Feb 17 '17 at 02:38
3

I often use return(NULL) for in the beginning of a function enclosed in some consistency checks, e.g. whether an output file would be overwritten. e.g.

some_function <- function(output_filename, overwrite = FALSE) {
  if (file.exists(output_filename)) {
    if (!overwrite) {
      return(NULL)
    }
  }
}

In this case the calling some_function("file.path", overwrite = FALSE) would return NULL. You can prevent that by modifying the return to:

...
return(invisible(NULL))
...
loki
  • 9,816
  • 7
  • 56
  • 82
1

the arg variable is being destroyed. A function in R will return the value of the last statement executed in the function unless a return statement is explicitly called.

In your case a copy of arg is the return value of your function. Example:

alwaysReturnSomething = function()
{
  x = runif(1)
  if(x<0.5) 20  else 10
}
> for(x in 1:10) cat(alwaysReturnSomething())
20202020102010101020

or:

alwaysReturnSomething <- function(){}
> z=alwaysReturnSomething()
> z
NULL
crogg01
  • 2,446
  • 15
  • 35
1

This is curious behavior.

Basically derp(), it returns if you assign the output of derp(), and derp() does not return if you do not assign the result. This is because the assignment function (<-) returns using the invisible() function. see Make a function return silently for how that works.

You can see the same behavior with derp2:

derp2 <- function(arg) {
  invisible(arg + 3)
}
derp2(3)
# nothing
b <- derp2(3)
b
# 6
Community
  • 1
  • 1
pdb
  • 1,574
  • 12
  • 26
0

If you want a function to change the value of a variable in Global environment you can use <<- operator, but you still need to write the exact name of a variable in Global environment

derp <- function(arg){
  arg <- arg+3
  b<<-3
}

Try it and call b

Andrew
  • 45
  • 8