Skip to content
Back to formatted view

Raw Message

Message-ID: <20150521185023.1a1d4fb5@bossiaea>
Date: 2015-05-21T10:50:23Z
From: Berwin A Turlach
Subject: Feature or bug?
In-Reply-To: <555DA936.6000807@wiwi.hu-berlin.de>

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