While my question is related to this recent one, I suspect its answer(s) will have to do with the detailed workings of R's S4 object system.
What I would expect:
(TLDR; -- All indications are that as(4L, "numeric")
should dispatch to a function whose body uses as.numeric(4L)
to convert it to a "numeric"
vector.)
Whenever one uses as(object, Class)
to convert an object to the desired Class
, one is really triggering a behind-the-scenes call to coerce()
. coerce()
, in turn, has a bunch of methods that are dispatched to based on the signature of the function call -- here the class of its first and second arguments. To see a list of all available S4 coerce()
methods, one can run showMethods("coerce")
.
Doing so shows that there is only one method for converting to class "numeric"
. It's the one with signature from="ANY", to="numeric"
:
showMethods("coerce")
# Function: coerce (package methods)
# from="ANY", to="array"
# ... snip ...
# from="ANY", to="numeric"
# ... snip ...
That method uses as.numeric()
to perform its conversion:
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"
Given its signature, and the fact that it's the only coerce()
method for conversion to class "numeric"
,
I would've expected that the function shown above is what would be dispatched to by a call to as(4L, "numeric")
.
That expectation is only reinforced by running the following two checks.
## (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"
What actually happens:
(TLDR; In fact, calling as(4L, "numeric")
loads and dispatches to a method that does nothing at all.)
Despite what all indications mentioned above, as(4L, "numeric")
does not dispatch to the coerce()
method for calls with signature c("ANY", "numeric")
.
Here are a couple of ways to show that:
## (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's 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")
What method, then, is used? Well, apparently the act of calling as(4L, "numeric")
adds a new S4 method to the list of methods for coerce()
, and it's what is used.
(Compare the results of the following calls to what they produced before we had attempted our
first "integer"
to "character"
conversion.)
## 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's 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"
My questions:
Why does as(4L, "numeric")
not dispatch to the available coerce()
method for signature=c("ANY", "numeric")
?
How/why does it instead add a new method to the S4 methods table?
From where (in R's source code or elsewhere) does the definition of the coerce()
method for signature=c("integer", "numeric")
come?
question from:
https://stackoverflow.com/questions/34141757/why-for-an-integer-vector-x-does-asx-numeric-trigger-loading-of-an-additi