Значение/ссылочное равенство для той же именованной функции в среде пакета/пространства имен?

Позволяет захватить среды "пространство имен: статистика" и "пакет: статистика"

ns = getNamespace( "stats" )
pkg = as.environment( "package:stats" )

Теперь давайте получим функцию "sd" в обоих:

nsSd = get( "sd" , envir = ns , inherits = FALSE )
pkgSd = get( "sd" , envir = pkg , inherits = FALSE )
Они одинаковы? Они есть! Но что означает "то же самое"? Ссылка или значение равенства?
identical( nsSd , pkgSd )

Это означает ссылочное равенство, так как следующее возвращает FALSE:

test1 = function() {}
test2 = function() {}
identical( test1 , test2 )

Но если это правда, это означает, что кадр среды может содержать указатели на функции вместе с объектами функции. Дальнейшее усложнение проблемы - факт, что функция может "жить" в одной среде, но функции можно сказать, что ее исполняющая среда является другой средой. Chambers SoDA, похоже, не имеет ответа (его плотная книга, может быть, я пропустил это!)

Итак, я бы хотел дать окончательный ответ. Что из следующего верно? Или здесь есть ложная трихотомия?

  • nsSd и pkgSd - это два разных объекта (хотя копии каждого другое), где объект в pkgSd имеет ns в качестве его выполнения окружающая среда
  • nsSd и pkgSd являются указателями на один и тот же объект.
  • nsSd является указателем на pkgSd и как таковой они рассматриваются как идентичные

Ответ 1

Они являются указателями на один и тот же объект. Используя этот ответ на другой вопрос, мы можем проверить, ссылаются ли два объекта на одно и то же место в памяти.

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

Ответ 2

Это не является главным ответом на ваш основной вопрос. Однако по этому вопросу я согласен с Dirk: существует только одна функция sd(), и к ней можно получить доступ, в зависимости от обстоятельств, с помощью разных областей охвата. Например, при вводе sd(x) в командной строке функция, соответствующая имени sd, будет найдена через ее запись в кадре среды package:stats. Когда вы вводите stats:::sd(x) или когда другая функция в пакете stats вызывает sd(x), она будет найдена с помощью поиска в среде namespace:stats.


Вместо этого я просто хотел подчеркнуть, что ваш пример с использованием test1() и test2() на самом деле не означает ничего о "ссылочном равенстве" объектов, которые оценивают до identical. Чтобы увидеть реальную причину, что эти два не identical, посмотрите на их структуру, как показано 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> 

Если вы перейдете к правой части окна кода выше, вы увидите, что две функции отличаются одним из своих атрибутов, а именно средой, связанной с их исходными файлами. (Я мало знаю об этом атрибуте, но это не очень важно здесь. Дело в том, что они не identical!)

Если вы сообщите R, что не хотите сохранять атрибуты атрибутов исходного файла с каждой созданной функцией, "неожиданное" поведение identical(test1, test2) исчезает:

options(keep.source=FALSE)
test1 <- function() {}
test2 <- function() {}
identical( test1 , test2 )
# [1] TRUE