Lets grab the environments "namespace:stats" and "package:stats"
ns = getNamespace( "stats" )
pkg = as.environment( "package:stats" )
Now lets get the function "sd" in both:
nsSd = get( "sd" , envir = ns , inherits = FALSE )
pkgSd = get( "sd" , envir = pkg , inherits = FALSE )
Are they the same? They are! But what does "same" mean? Reference or value equality?
identical( nsSd , pkgSd )
This implies reference equality, since the following returns FALSE:
test1 = function() {}
test2 = function() {}
identical( test1 , test2 )
But if that's true, it means that an Environment's frame can contain function pointers alongside function objects. Further complicating the issue is fact that a function can "live" in one environment, but the function can be told that its executing environment is another environment. Chambers SoDA doesn't seem to have an answer (its a dense book, maybe I missed it!)
So, I'd like a definitive answer. Which of the following are correct? Or is there a false trichotomy here?
nsSd
and pkgSd
are two different objects (albeit copies of each
other), where the object in pkgSd
has ns
as its executing
environmentnsSd
and pkgSd
are pointers to the same object. nsSd
is a pointer to pkgSd
and as such they are treated as identicalThey are pointers to the same object. Using this answer to another question, we can check if two objects refer to the same place in memory.
are_same <- function(x, y)
{
f <- function(x) capture.output(.Internal(inspect(x)))
all(f(x) == f(y))
}
are_same(nsSd, pkgSd) #TRUE
are_same(1:5, 1:5) #FALSE
This isn't mostly an answer to your main question. On that issue, though, I agree with Dirk: there is just one sd()
function, and it can be accessed, depending on the circumstances, by different scoping paths. For instance, when you type sd(x)
at the command line, the function corresponding to the name sd
will be found via its entry in the frame of the package:stats
environment. When you type stats:::sd(x)
, or when another function in stats
package calls sd(x)
, it will be found via a search in the namespace:stats
environment.
Instead, I just wanted to make the point that your example using test1()
and test2()
doesn't really imply anything about the "reference equality" of objects that do evaluate to identical
. To see the real reason those two are not identical
, have a look at their structure as revealed by str()
:
test1 <- function() {}
test2 <- function() {}
identical( test1 , test2 )
# [1] FALSE
str(test1)
# function ()
# - attr(*, "srcref")=Class 'srcref' atomic [1:8] 1 13 1 25 13 25 1 1
# .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x01613f54>
str(test2)
# function ()
# - attr(*, "srcref")=Class 'srcref' atomic [1:8] 1 13 1 25 13 25 1 1
# .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x01615730>
If you scroll over to the right side of the code box above, you will see that the two functions differ in one of their attributes, namely the environment associated with their source files. (I don't know much about that attribute, but that's not really relevant here. The point is that they're not identical
!)
If you tell R that you don't want to keep sourcefile attribute data with every function that's created, the 'unexpected' behavior of identical(test1, test2)
goes away:
options(keep.source=FALSE)
test1 <- function() {}
test2 <- function() {}
identical( test1 , test2 )
# [1] TRUE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With