is.object и система классов S3

Использование функции class позволяет нам определить класс объекта:

> x = 5
> class(x)
[1] "numeric"

Я также понимаю, что мы можем использовать команду is.object, чтобы определить, есть ли у объекта класс. Однако некоторые типы объектов являются неявными, т.е.

> is.object(x)
[1] FALSE

Правильно ли было бы утверждать, что все переменные в R являются объектами, а is.object является тестом только для неявных классов?

Кроме того, как типы вписываются в это. По наивности я думал, что следующий фрагмент кода выдаст ошибку:

> x = 5
> class(x) = "fake"
> x = X + 1
> x + 1
[1] 6
attr(,"class")
[1] "fake"

Но x все равно имеет тип "двойной", все равно все работает. Можно ли рассматривать типы как суперкласс, от которого наследуются все остальные объекты?


person csgillespie    schedule 18.01.2011    source источник
comment
Хотя есть тег s4, тега s3 нет. Кто-нибудь создаст тег s3?   -  person csgillespie    schedule 18.01.2011
comment
Я думал, что ретегов будет достаточно, похоже нет :-(   -  person cadrian    schedule 18.01.2011
comment
s3, по-видимому, является синонимом amazon-s3. Я задал вопрос о мета о том, как это сделать: meta.stackexchange.com/questions/75332/   -  person Joris Meys    schedule 18.01.2011


Ответы (2)


typeof возвращает тип внутреннего представления C и не используется для отправки метода. Так что, строго говоря, вы не можете думать о типах как о «суперклассах».

Вместо этого есть базовые классы (числовой, символьный, список, функция и т. д.), которые примерно соответствуют именам, возвращаемым typeof, но не всегда (например, тип double относится к числовому классу, специальный и замыкающий — к функция класса, а класс data.frame имеет тип список!).

В системах S3 и S4 вы можете создавать нетривиальные классы, используя базовые классы (но не обязательно расширять один из них!! Пример: setClass("foo", list(a="numeric",b="character") не расширяет ни один из базовых классов).

Для объектов из этих базовых классов is.object возвращает FALSE. Как сказано в документации, эта функция предоставляет очень быстрый способ проверить, относится ли объект к пользовательскому классу S3 или S4 (т. е. не к одному из базовых классов).

После приведения x к "подделке" ваш объект формально не относится к "числовому" классу:

is(x, "numeric")
#FALSE

но он интерпретируется как базовый «числовой» объект:

is.numeric(x)
#TRUE

Вот почему здесь работает +. Итак, внутри, как уже сказал @Richie, метод по умолчанию интерпретирует x как числовой базовый класс.

Этот концептуальный беспорядок происходит из-за неформального отношения S3 к классам. Вместо этого используйте S4.


соответствие между typeof(.) и базовым class(.):

                              typeof(.)  class(.)
NULL                          "NULL"     "NULL"
1                             "double"   "numeric"
1:1                           "integer"  "integer"
1i                            "complex"  "complex"
list(1)                       "list"     "list"
data.frame(x=1)               "list"     "data.frame"
pairlist(pi)                  "pairlist" "pairlist"
c                             "special"  "function"
lm                            "closure"  "function"
formals(lm)[[1]]              "symbol"   "name"
formals(lm)[[2]]              "symbol"   "name"
y~x                           "language" "formula"
expression((1))[[1]]          "language" "("
(y~x)[[1]]                    "symbol"   "name"
expression(x <- pi)[[1]][[1]] "symbol"   "name"
person VitoshKa    schedule 18.01.2011
comment
S4 представляет свой собственный набор проблем. Я не думаю, что стоит советовать использовать S4 вместо S3, не зная больше о проблеме. - person hadley; 15.11.2011
comment
@hadley По моему опыту, проблемы с S4 возникают в основном из-за грязной и непрозрачной реализации — она полна внутренних обходных путей и исправлений. Это часто приводит к неожиданным результатам, и лично мне это тоже очень надоело. Сама система имитирует объектную систему Common Lisp, которая широко известна как одна из самых гибких и надежных объектных ориентаций. Кроме того, тот факт, что R становится все более и более похожим на S4, является хорошей причиной для использования S4, а не S3. - person VitoshKa; 07.01.2012
comment
c должна быть встроенной, а не специальной функцией: проверьте это с помощью typeof(c). - person Erdogan CEVHER; 18.07.2018

Частичный ответ на первый вопрос можно найти в главе 2 определения языка R.

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

Итак, да, все переменные являются объектами.

is.object кажется более или менее эквивалентным function(x) !is.null(attr(x, "class")), но я готов ошибаться в этом.

Что касается второго вопроса, я думаю, что происходит следующее: поскольку x имеет класс «fake», R ищет метод +.fake в добавлении, но когда не находит, прибегает к методу по умолчанию. Этот метод по умолчанию основан на базовом коде C, который использует typeof(x) (или эквивалент C) для определения того, что следует делать. В этом случае тип x — «целый».

person Richie Cotton    schedule 18.01.2011
comment
Это немного сложнее. Ключ к поиску внутренних дженериков. Напишу больше, когда не на телефоне - person hadley; 18.01.2011