Search code examples
rshinyreactive

Basic return behavior of reactive


Despite reading many tutorials, it's still fundamentally unclear to me what is being passed back from a reactive expression/code block, especialy when code blocks inside reactive become longer. I did some basic tests, assuming reactiveConsole(TRUE) is a proper way of testing these things.

Is the following summary accurate?

  • without an explicit return statement, reactive always returns the value produced by the last statement within its expression, regardless of whether that value was assigned to a local variable (but see "unexpected" behavior in examples below)
  • use explicit return statement(s) to prevent returning the result of the final statement, for example to avoid returning a debugging print statement at the end of the expression, to build in if/else logic on what to return, etc.

If there are other important variations on or exceptions to this behavior worth mentioning, please do.

library(shiny)
reactiveConsole(TRUE)

#------single line-----
#direct assignment
x = reactive({5})
x() #-> 5

ans = x()
ans #-> 5

#assign value to local variable, return
x = reactive({tmp = 5
return(tmp)})
x() #-> 5

ans = x()
ans #-> 5

#assign value to local variable, don't return
x = reactive({tmp = 5})
x() #-> [no response]

ans = x()
ans #-> 5 [value unexpectedly returns]


#-----multi-line---
#direct assignment: final line is retained
x = reactive({5
  10})
x() #-> 10

ans = x()
ans #-> 10


#return requested local var, tmp
x = reactive({tmp = 5
tmp2 = 10
return(tmp)})
x() #-> 5

ans = x()
ans #-> 5

#return requested local var, tmp2
x = reactive({tmp = 5
tmp2=10
return(tmp2)})
x() #-> 10

ans = x()
ans #-> 10

#without return
x = reactive({tmp = 5
tmp2 = 10})
x() #-> [no response]

ans = x()
ans #-> 10 [value unexpectedly returns]

Solution

  • I don't know reactive(), but the behaviour you saw is exactly the same as a standard function or block of code in braces. If your function is

    f <- function() {
       x <- 5
    }
    

    then calling f() doesn't print anything, but it returns the value 5, because the statement x <- 5 returns the value 5 "invisibly". In R, things returned invisibly don't auto-print, and the value of the last statement executed in the body of the function is the default return value of the function.

    The same is true of the code block

    {
      x <- 5
    }