[R] Feature or bug?

William Dunlap wdunlap at tibco.com
Thu May 21 17:03:01 CEST 2015


If you add a print statement to trace the evaluation of the input argument
you can see how the lazy evaluation works:

> update <- function (newtime) {
    cat("# update() is changing global ginput's time from", ginput$time,
"to", newtime, "\n")
    ginput <<- list(time = newtime)
    }
> server <- function(input, doFirstPrint) {
    if (doFirstPrint) {
        cat("# Before calling update(1): input$time=", input$time,
"ginput$time=", ginput$time, "\n")
    }
    update(1)
    cat("# After calling update(1): input$time=", input$time,
"ginput$time=", ginput$time, "\n")
    }
> ginput <- list(time=0)
> server({cat("# Evaluating server's 'input' argument\n"); ginput},
doFirstPrint=TRUE)
# Evaluating server's 'input' argument
# Before calling update(1): input$time= 0 ginput$time= 0
# update() is changing global ginput's time from 0 to 1
# After calling update(1): input$time= 0 ginput$time= 1
> ginput <- list(time=0)
> server({cat("# Evaluating server's 'input' argument\n"); ginput},
doFirstPrint=FALSE)
# update() is changing global ginput's time from 0 to 1
# Evaluating server's 'input' argument
# After calling update(1): input$time= 1 ginput$time= 1


Bill Dunlap
TIBCO Software
wdunlap tibco.com

On Thu, May 21, 2015 at 7:48 AM, peter dalgaard <pdalgd at gmail.com> wrote:

>
> On 21 May 2015, at 16:26 , Bert Gunter <gunter.berton at gene.com> wrote:
>
> > Well..
> >
> > "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."
> >
> > While I may be either wrong or just picking on semantics, I don't
> > think so. It is merely what you stated previously: input was assigned
> > a value in the local server function environment, and that assignment
> > was not affected by the subsequent assignment to the global
> > environment. So it is a matter of R's semantics -- where it looks for
> > the values bound to symbols -- rather than lazy evaluation.
> >
> > Obviously then, a simple way to do what the OP seemed to want would be
> > to simply assign the updated value in the local function environment,
> > rather than the global. I get nervous whenever I see constructs with
> > eval(substitute...)) or global assignments from within a function.
> > Both have their place, of course, but (the latter especially) can be
> > dangerous, and my experience both on the list and with my own code, is
> > that if you think you need them, you probably should rethink what you
> > need to do.
> >
> > Corrections and/or criticism of these comments are welcome.
> >
>
> Berwin is right, or rather: There are two issues. The "input" argument to
> server() is evaluated when first used. The difference between the two
> examples is whether this happens before or after update(), and that is the
> effect of lazy evaluation. The fact that it in the first case the value is
> unchanged by the update is due to scoping: Once evaluate "input" becomes a
> local variable  an is unchanged by assignment to the global variable.
>
> -pd
>
>
> > Best,
> > Bert
> >
> >
> >
> > Bert Gunter
> > Genentech Nonclinical Biostatistics
> > (650) 467-7374
> >
> > "Data is not information. Information is not knowledge. And knowledge
> > is certainly not wisdom."
> > Clifford Stoll
> >
> >
> >
> >
> > On Thu, May 21, 2015 at 3:50 AM, Berwin A Turlach
> > <Berwin.Turlach at gmail.com> wrote:
> >> 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
> >>
> >> ______________________________________________
> >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> >> https://stat.ethz.ch/mailman/listinfo/r-help
> >> PLEASE do read the posting guide
> http://www.R-project.org/posting-guide.html
> >> and provide commented, minimal, self-contained, reproducible code.
> >
> > ______________________________________________
> > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> > https://stat.ethz.ch/mailman/listinfo/r-help
> > PLEASE do read the posting guide
> http://www.R-project.org/posting-guide.html
> > and provide commented, minimal, self-contained, reproducible code.
>
> --
> Peter Dalgaard, Professor,
> Center for Statistics, Copenhagen Business School
> Solbjerg Plads 3, 2000 Frederiksberg, Denmark
> Phone: (+45)38153501
> Office: A 4.23
> Email: pd.mes at cbs.dk  Priv: PDalgd at gmail.com
>
> ______________________________________________
> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide
> http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>

	[[alternative HTML version deleted]]



More information about the R-help mailing list