Feature or bug?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Feature or bug?

Sigbert Klinke
Hi,

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"

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"

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.

Sigbert

--
http://u.hu-berlin.de/sk
______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: Feature or bug?

Berwin A Turlach-3
G'day Sigbert,

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

On Thu, 21 May 2015 11:45:26 +0200
Sigbert Klinke <[hidden email]> 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: [hidden email]
Australia                http://www.maths.uwa.edu.au/~berwin
                         http://www.researcherid.com/rid/A-4995-2008

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: Feature or bug?

Bert Gunter
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.

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
<[hidden email]> wrote:

> G'day Sigbert,
>
> long time no see :)
> How is Berlin these days?
>
> On Thu, 21 May 2015 11:45:26 +0200
> Sigbert Klinke <[hidden email]> 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: [hidden email]
> Australia                http://www.maths.uwa.edu.au/~berwin
>                          http://www.researcherid.com/rid/A-4995-2008
>
> ______________________________________________
> [hidden email] 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.

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: Feature or bug?

Peter Dalgaard-2

On 21 May 2015, at 16:26 , Bert Gunter <[hidden email]> 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
> <[hidden email]> wrote:
>> G'day Sigbert,
>>
>> long time no see :)
>> How is Berlin these days?
>>
>> On Thu, 21 May 2015 11:45:26 +0200
>> Sigbert Klinke <[hidden email]> 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: [hidden email]
>> Australia                http://www.maths.uwa.edu.au/~berwin
>>                         http://www.researcherid.com/rid/A-4995-2008
>>
>> ______________________________________________
>> [hidden email] 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.
>
> ______________________________________________
> [hidden email] 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: [hidden email]  Priv: [hidden email]

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: Feature or bug?

William Dunlap
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 <[hidden email]> wrote:

>
> On 21 May 2015, at 16:26 , Bert Gunter <[hidden email]> 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
> > <[hidden email]> wrote:
> >> G'day Sigbert,
> >>
> >> long time no see :)
> >> How is Berlin these days?
> >>
> >> On Thu, 21 May 2015 11:45:26 +0200
> >> Sigbert Klinke <[hidden email]> 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: [hidden email]
> >> Australia                http://www.maths.uwa.edu.au/~berwin
> >>                         http://www.researcherid.com/rid/A-4995-2008
> >>
> >> ______________________________________________
> >> [hidden email] 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.
> >
> > ______________________________________________
> > [hidden email] 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: [hidden email]  Priv: [hidden email]
>
> ______________________________________________
> [hidden email] 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]]

______________________________________________
[hidden email] 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.