https://plus.google.com/u/0/113855172046033123438/posts/P8AxUnCopK2
fun <- local({
count <- 0
function(i = 1) {
count <<- count + i
count
}
})
### some doodles to get you thinking and tinkering..
fun()
## [1] 1
fun()
## [1] 2
fun(4)
## [1] 6
attach(environment(fun))
count
## [1] 6
fun(-4)
## [1] 2
fun()
## [1] 3
So what's it doing?
fun <- local({ # a function created in the local env.
count <- 0 # count starts at 0
function(i = 1) { # within this env. a function adds i
count <<- count + i # and super-assigns it to count (in local env.)
count # the function then returns this count value
}
})
environment {base}
The global environment .GlobalEnv, more often known as the user's workspace, is the first item on the search path. It can also be accessed by globalenv(). On the search path, each item's enclosure is the next item.
[…]
If
funis a function or a formula then environment(fun) returns the environment associated with that function or formula. If fun is NULL then the current evaluation environment is returned.
ls() # only 'fun' exists in this env.
## [1] "fun"
ls(envir = .GlobalEnv) # ...the .GlobalEnv
## [1] "fun"
ls(envir = local) # can't access local this way ??
## Error: invalid 'envir' argument
ls(envir = .local) # or this way ??
## Error: object '.local' not found
ls {base} The name argument can specify the environment from which object names are taken in one of several forms: as an integer (the position in the search list); as the character string name of an element in the search list; or as an explicit environment (including using sys.frame to access the currently active function calls).
[…]
ls.str for a long listing based on str. apropos (or find) for finding objects in the whole search path; …
ls(1) # 1 = .GlobalEnv, 1st in search list
## [1] "fun"
ls(2) # count is within local env., 2nd in search path
## [1] "count"
ls.str {utils}
lsf.str(pos = -1, envir, …)
[…]
lsf.str() #- how do the functions look like which I am using? ls.str(mode = “list”) #- what are the structured objects I have defined?
[…]
.# demonstrating that ls.str() works inside functions …
lsf.str(.GlobalEnv)
## fun : function (i = 1)
fun <- local({ # the local env.
count <- 0 # count
function(i = 1) { # within this a function
count <<- count + i # super-assigns count (but where)?
## count # instead of count value
ls.str() # return List Objects and their Structure
}
})
fun
## function(i = 1) { # within this a function
## count <<- count + i # super-assigns count (but where)?
## ## count # instead of count value
## ls.str() # return List Objects and their Structure
## }
## <environment: 0x00000000077fd8f8>
That doesn't return count but does return the function.
Try -1, as position in search list.
lsf.str(pos = -1) # .GlobalEnv
## fun : function (i = 1)
lsf.str(pos = 2) # nothing returned from local though
So is a local env., accessible from the .GlobalEnv?
Check what local does…
eval {base}
…
localevaluates an expression in a local environment. … its default argument creates a new, empty environment. This is useful to create anonymous recursive functions and as a kind of limited namespace feature since variables defined in the environment are not visible from the outside.
Hmm. This seems like an anonymous recursive function, the variable count defined within it seems invisble from the outside.
Is the distinction between normal assignment of count within the local env. and the persistance of count created by super-assignment?
Return to the original function:
fun <- local({
count <- 0
function(i = 1) {
count <<- count + i
count
}
})
Now, what's it doing?
### some doodles to get you thinking and tinkering..
fun() # added 1 to 0
## [1] 1
fun() # it kept count
## [1] 2
fun(4) # and added 4 to 2
## [1] 6
attach(environment(fun)) # go into the env of `fun`
## The following object is masked from environment(fun) (position 3):
##
## count
count # count is 6, result of <<- count + i
## [1] 6
# inside `fun` env, it creates another local env. (pos = 3)
fun(-4) # hence warning "object is masked from environment(fun) (position 3)"
## [1] 2
fun() # so without a value it will add 1 by default
## [1] 3
And finally, check help for <<-
?<<- # no, be careful
?`<<-` # yes
The operators
<<-and->>are normally only used in functions, and cause a search to made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment. … See The R Language Definition manual for further details and examples.
So <<- causes a search through parent environments for an existing definition of the variable being assigned (e.g. count).
So <<- is best contained under another assignment of the same name, and both contained within a local environment.
Otherwise count gets assigned in the .GlobalEnv, unintentionally, breaking the intended evaluation and risking over-writing an object in the .GlobalEnv.