В то время как мой вопрос связан с этим недавним, я подозреваю, что его ответ будет связан с подробными разработками объектной системы R S4.
Что бы я ожидал:
( TL;DR; - все указывает на то, что as(4L, "numeric")
должен отправить функцию, чье тело использует as.numeric(4L)
, чтобы преобразовать ее в вектор "numeric"
.)
Всякий раз, когда вы используете as(object, Class)
для преобразования объекта в желаемый Class
, на самом деле запускается за кадром вызов coerce()
. coerce()
, в свою очередь, имеет множество методов, которые отправляются на основе сигнатуры вызова функции - здесь класс его первого и второго аргументов. Чтобы просмотреть список всех доступных методов S4 coerce()
, можно запустить showMethods("coerce")
.
Это показывает, что существует только один способ преобразования в класс "numeric"
. Он имеет подпись from="ANY", to="numeric"
:
showMethods("coerce")
# Function: coerce (package methods)
# from="ANY", to="array"
# ... snip ...
# from="ANY", to="numeric"
# ... snip ...
Этот метод использует as.numeric()
для выполнения его преобразования:
getMethod("coerce", c("ANY", "numeric"))
# Method Definition:
#
# function (from, to, strict = TRUE)
# {
# value <- as.numeric(from)
# if (strict)
# attributes(value) <- NULL
# value
# }
# <environment: namespace:methods>
#
# Signatures:
# from to
# target "ANY" "numeric"
# defined "ANY" "numeric"
Учитывая его подпись и тот факт, что он единственный метод coerce()
для преобразования в класс "numeric"
,
Я бы ожидал, что функция, показанная выше, будет отправлена вызовом as(4L, "numeric")
.
Это ожидание подкрепляется только проведением следующих двух проверок.
## (1) There isn't (apparently!) any specific method for "integer"-->"numeric"
## conversion
getMethod("coerce", c("integer", "numeric"))
# Error in getMethod("coerce", c("integer", "numeric")) :
# no method found for function 'coerce' and signature integer, numeric
## (2) This says that the "ANY"-->"numeric" method will be used for "integer"-->"numeric"
## conversion
selectMethod("coerce", signature=c("integer", "numeric"))
# Method Definition:
#
# function (from, to, strict = TRUE)
# {
# value <- as.numeric(from)
# if (strict)
# attributes(value) <- NULL
# value
# }
# <environment: namespace:methods>
#
# Signatures:
# from to
# target "integer" "numeric"
# defined "ANY" "numeric"
Что на самом деле происходит:
( TL;DR; На самом деле вызов as(4L, "numeric")
загружает и отправляет метод, который ничего не делает.)
Несмотря на то, что все признаки, упомянутые выше, as(4L, "numeric")
не отправляет метод coerce()
для вызовов с сигнатурой c("ANY", "numeric")
.
Вот несколько способов показать, что:
## (1) as.numeric() would do the job, but as(..., "numeric") does not
class(as(4L, "numeric"))
#[1] "integer"
class(as.numeric(4L))
# [1] "numeric"
## (2) Tracing shows that the "generic" method isn't called
trace("coerce", signature=c("ANY", "numeric"))
as(c(FALSE, TRUE), "numeric") ## <-- It called for "logical" vectors
# Tracing asMethod(object) on entry
# [1] 0 1
as(c("1", "2"), "numeric") ## <-- and for "character" vectors
# Tracing asMethod(object) on entry
# [1] 1 2
as(c(1L, 2L), "numeric") ## <-- but not for "integer" vectors
# [1] 1 2
untrace("coerce")
Какой метод используется? Ну, по-видимому, акт вызова as(4L, "numeric")
добавляет новый метод S4 в список методов для coerce()
, и это то, что используется.
(Сравните результаты следующих обращений к тому, что они произвели, прежде чем мы попытались
сначала преобразование "integer"
в "character"
.)
## At least one conversion needs to be attempted before the
## "integer"-->"numeric" method appears.
as(4L, "numeric")
## (1) Now the methods table shows a new "integer"-->"numeric" specific method
showMethods("coerce")
# Function: coerce (package methods)
# from="ANY", to="array"
# ... snip ...
# from="ANY", to="numeric"
# ... snip ...
# from="integer", to="numeric" ## <-- Here the new method
# ... snip ...
## (2) selectMethod now tells a different story
selectMethod("coerce", signature=c("integer", "numeric"))
# Method Definition:
#
# function (from, to = "numeric", strict = TRUE)
# if (strict) {
# class(from) <- "numeric"
# from
# } else from
# <environment: namespace:methods>
#
# Signatures:
# from to
# target "integer" "numeric"
# defined "integer" "numeric"
Мои вопросы:
-
Почему
as(4L, "numeric")
не отправляет доступный методcoerce()
дляsignature=c("ANY", "numeric")
? -
Как/почему он вместо этого добавляет новый метод в таблицу методов S4?
-
Откуда (в исходном коде R или где-нибудь еще) выполняется ли определение метода
coerce()
дляsignature=c("integer", "numeric")
?