[R] Feature or bug?

Berwin A Turlach Berwin.Turlach at gmail.com
Thu May 21 12:50:23 CEST 2015


G'day Sigbert,

long time no see :)
How is Berlin these days?

On Thu, 21 May 2015 11:45:26 +0200
Sigbert Klinke <sigbert at wiwi.hu-berlin.de> wrote:

It is a feature.

> if I run
> 
> update <- function (newtime) { ginput <<- list(time=newtime)}
> 
> server <- function (input) {
>   print(paste("Before", input$time))
>   update(1)
>   print(paste("After:", input$time))
> }
> 
> ginput <- list(time=0)
> server(ginput)
> 
> then I get as result
> 
> [1] "Before 0"
> [1] "After: 0"

The first print command evaluates input and after this the function
server has an object named "input" in its local environment.  The
second print command reuses this object and extracts the component time
from it (which has not changed).  The change of the global variable has
no effect.

> If I uncomment the first print
> 
> update <- function (newtime) { ginput <<- list(time=newtime) }
> 
> server <- function (input) {
>   #print(paste("Before", input$time))
>   update(1)
>   print(paste("After:", input$time))
> }
> 
> ginput <- list(time=0)
> server(ginput)
> 
> then I get
> 
> [1] "After: 1"

Because the global variable is changed before input is evaluated.  R
has lazy argument evaluation, arguments are only evaluated once they
are needed.  You are essentially getting bitten by R's lazy evaluation
plus "pass by value" syntax.

> Even when I use a side effect (by assign some new value to a global
> variable) I would have expected the same behaviour in both cases.

To get the behaviour that you expect, you would have to write your code
along the following lines:

R> update <- function (newtime) { ginput <<- list(time=newtime)}
R> server <- function(input){
+     inp <- as.name(deparse(substitute(input)))
+     print(paste("Before", eval(substitute(XXX$time, list(XXX=inp)))))
+     update(1)
+     print(paste("After:", eval(substitute(XXX$time, list(XXX=inp)))))
+ }
R> ginput <- list(time=0)
R> server(ginput)
[1] "Before 0"
[1] "After: 1"


A cleaner way is perhaps to use environments, as these are passed by
reference:

R> update <- function(env, newtime) env$time <- newtime
R> server <- function(input){
+     print(paste("Before", input$time))
+     update(input, 1)
+     print(paste("After:", input$time))
+ }
R> ginput <- new.env()
R> ginput$time <- 0
R> server(ginput)
[1] "Before 0"
[1] "After: 1"

HTH.

Cheers,

	Berwin

========================== Full address ============================
A/Prof Berwin A Turlach               Tel.: +61 (8) 6488 3338 (secr)
School of Maths and Stats (M019)            +61 (8) 6488 3383 (self)
The University of Western Australia   FAX : +61 (8) 6488 1028
35 Stirling Highway                   
Crawley WA 6009                     e-mail: Berwin.Turlach at gmail.com
Australia                http://www.maths.uwa.edu.au/~berwin
                         http://www.researcherid.com/rid/A-4995-2008



More information about the R-help mailing list