Hi, The code below creates a value, x$a, which depending on how you access it evaluates to its initial value, or to what it's been changed to. The last two lines should, I would have thought, evaluate to the same value, but they don't. f <- function () { x <- NULL; x$a <- 0; x$get.a <- function () { x$a; }; x$increment.a <- function () { x$a <<- x$a + 5; }; x }; x <- f(); x$increment.a(); x$get.a(); x$a; This can be repeated; each time you call x$increment.a(), the value displayed by x$get.a() changes, but x$a continues to be zero. Is that totally weird, or what? Thanks, Jeff -- View this message in context: http://n4.nabble.com/Scope-and-assignment-baffling-tp1747582p1747582.html Sent from the R help mailing list archive at Nabble.com.
Jeff Brown wrote:> Hi, > > The code below creates a value, x$a, which depending on how you access it > evaluates to its initial value, or to what it's been changed to. The last > two lines should, I would have thought, evaluate to the same value, but they > don't. > > f <- function () { > x <- NULL; > x$a <- 0; > x$get.a <- function () { > x$a; > }; > x$increment.a <- function () { > x$a <<- x$a + 5; > }; > x > }; > x <- f(); > x$increment.a(); > x$get.a(); > x$a; > > This can be repeated; each time you call x$increment.a(), the value > displayed by x$get.a() changes, but x$a continues to be zero. > > Is that totally weird, or what?In a word, no. It's not the same x. (And R is not Java or C++). It should be enlightening to try evalq(x,environment(x$get.a)) -- Peter Dalgaard Center for Statistics, Copenhagen Business School Phone: (+45)38153501 Email: pd.mes at cbs.dk Priv: PDalgd at gmail.com
> -----Original Message----- > From: r-help-bounces at r-project.org > [mailto:r-help-bounces at r-project.org] On Behalf Of Jeff Brown > Sent: Wednesday, March 31, 2010 6:45 PM > To: r-help at r-project.org > Subject: [R] Scope and assignment: baffling > > > Hi, > > The code below creates a value, x$a, which depending on how > you access it > evaluates to its initial value, or to what it's been changed > to. The last > two lines should, I would have thought, evaluate to the same > value, but they > don't. > > f <- function () { > x <- NULL;It would be better to say x <- list() instead of x<-NULL, since the following x$a<- coerces it to a list.> x$a <- 0; > x$get.a <- function () { > x$a; > }; > x$increment.a <- function () { > x$a <<- x$a + 5; > }; > x > }; > x <- f();Let's make things a tad clearer by naming the output of f() 'globalX': globalX <- f() globalX is a list containing a [virtual] copy of f's x, as it stood when f() returned it. You cannot modify globalX without doing something like globalX$something<-xxx. f's x remains in the environment created when you ran f(). Each time you run f() you create an new environment (with a new version of f's x). A function's evaluation environment generally goes away when the function is done, but it remains if there are any references to the environment from f()'s return value. If the return value contains functions defined in f() then they refer to f()'s evaluation environment, so it hangs around. When you run globalX$increment.a() you are modifying f()'s environment's x$a, not globalX$a. Usually such function are written so the state variables are not in the output structure, as in: f <- function() { fA <- 0 retval <- list() retval$get.a <- function() { fA } retval$increment.a <- function() { fA <<- fA + 5 } retval } Then you can use it as you did but it is clear that retval itself doesn't contain any state. You can find the possible state variables with > globalX <- f() > globalX$increment.a() > objects(environment(globalX$get.a)) [1] "fA" "retval" > eval(quote(fA), environment(globalX$get.a)) [1] 5 > globalX$increment.a() > eval(quote(fA), environment(globalX$get.a)) [1] 10 > globalX$get.a() [1] 10 The output of objects() suggests you might want to clean up the code by not naming 'retval', just returning list(get.a=function()fA, ...). Then your environment won't carry around an unused copy of retval. Bill Dunlap Spotfire, TIBCO Software wdunlap tibco.com> x$increment.a(); > x$get.a(); > x$a; > > This can be repeated; each time you call x$increment.a(), the value > displayed by x$get.a() changes, but x$a continues to be zero. > > Is that totally weird, or what? > > Thanks, > Jeff > -- > View this message in context: > http://n4.nabble.com/Scope-and-assignment-baffling-tp1747582p1747582.html> Sent from the R help mailing list archive at Nabble.com. > > ______________________________________________ > R-help at r-project.org mailing list > 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. >
The code you presented is very close to object oriented in the style of the proto package. For example, library(proto) # generate a single object p p <- proto(a = 0, geta = function(.) .$a, incra = function(.) .$a <- .$a + 5) p$geta() p$a # same p$incra() p$geta() # Or if you want to be able to generate objects like that: Account <- function() proto(a = 0, geta = function(.) .$a, incra = function(.) .$a <- .$a + 5) # pp is an Account object pp <- Account() pp$geta() pp$a # same pp$incra() pp$geta() See http://r-proto.googlecode.com for more info. On Wed, Mar 31, 2010 at 9:44 PM, Jeff Brown <dopethatwantscash at yahoo.com> wrote:> > Hi, > > The code below creates a value, x$a, which depending on how you access it > evaluates to its initial value, or to what it's been changed to. ?The last > two lines should, I would have thought, evaluate to the same value, but they > don't. > > f <- function () { > ? ? ? ?x <- NULL; > ? ? ? ?x$a <- 0; > ? ? ? ?x$get.a <- function () { > ? ? ? ? ? ? ? ?x$a; > ? ? ? ?}; > ? ? ? ?x$increment.a <- function () { > ? ? ? ? ? ? ? ?x$a <<- x$a + 5; > ? ? ? ?}; > ? ? ? ?x > }; > x <- f(); > x$increment.a(); > x$get.a(); > x$a; > > This can be repeated; each time you call x$increment.a(), the value > displayed by x$get.a() changes, but x$a continues to be zero. > > Is that totally weird, or what? > > Thanks, > Jeff > -- > View this message in context: http://n4.nabble.com/Scope-and-assignment-baffling-tp1747582p1747582.html > Sent from the R help mailing list archive at Nabble.com. > > ______________________________________________ > R-help at r-project.org mailing list > 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. >
Thanks, Bill! That was deep, and took me a long time to work through, but I get it now. And Gabor -- r-proto is great! -- View this message in context: http://n4.nabble.com/Scope-and-assignment-baffling-tp1747582p1753321.html Sent from the R help mailing list archive at Nabble.com.
Apparently Analagous Threads
- Reference classes: accessor functions via 'getRefClass(...)$accessors(...)'
- [cfe-dev] New warnings when building trunk with GCC 9
- best practice(s) for retrieving a local variable from a closure
- [cfe-dev] New warnings when building trunk with GCC 9
- baffling sort problem