Besides is()
and inherits()
we can also test objects with is.*()
for a certain type. Those three function can return different results. Based on this answer I did the following
- Created numerous R objects of different types
- Extracted the type of those objects using
storage.mode()
, mode()
, typeof()
and class()
.
- Tested the objects whether they are of the returned types using
is()
, inherits()
and is.*()
.
Here is a small example of the three steps above:
# Get object classes withs torage.mode(), mode(), typeof() and class().
obj <- logical()
(types <- c(storage.mode= storage.mode(obj),
mode= mode(obj),
type= typeof(obj),
class= class(obj)))
storage.mode mode type class
"double" "numeric" "double" "numeric"
# Test returned types with is, inhertis and is.*.
> is(obj, "double"); is(obj, "numeric")
[1] FALSE
[1] TRUE
> inherits(obj, "double"); inherits(obj, "numeric")
[1] FALSE
[1] TRUE
> is.double(obj); is.numeric(obj)
[1] TRUE
[1] TRUE
Now we do this for a bunch of object types with the following code:
# Generate objects of different types.
library(xml2)
setClass("dummy", representation(x="numeric", y="numeric"))
obj <- list(
"logical vector" = logical(),
"integer vector" = integer(),
"numeric vector" = numeric(),
"complex vector" = complex(),
"character vector" = character(),
"raw vector" = raw(),
"factor" = factor(),
"logical matrix" = matrix(logical()),
"numeric matrix" = matrix(numeric()),
"logical array" = array(logical(8), c(2, 2, 2)),
"numeric array" = array(numeric(8), c(2, 2, 2)),
"list" = list(),
"pairlist" = .Options,
"data frame" = data.frame(),
"closure function" = identity,
"builtin function" = `+`,
"special function" = `if`,
"environment" = new.env(),
"null" = NULL,
"formula" = y ~ x,
"expression" = expression(),
"call" = call("identity"),
"name" = as.name("x"),
#"paren in expression" = expression((1))[[1]], # Code fails with this
#"brace in expression" = expression({1})[[1]], # Code fails with this
"S3 lm object" = lm(dist ~ speed, cars),
"S4 dummy object" = new("dummy", x = 1:10, y = rnorm(10)),
"external pointer" = read_xml("<foo><bar /></foo>")$node
)
# Extract types and test them.
res <- do.call("rbind.data.frame", Map(function(x, name){
types <- c(storage.mode= storage.mode(x),
mode= mode(x),
type= typeof(x),
class= class(x))
data.frame("object"= name,
"extract_method"= names(types),
"extract_result"= types,
"inherits"= sapply(types, function(i) inherits(x, i)),
"is"= sapply(types, function(i) is(x, i)),
"is.type"= sapply(types, function(i) eval(parse(text= paste0("tryCatch({is.", i, "(x)}, error= function(e){'is.", i, "() does not exist'})"))))
)}, obj, names(obj)))
rownames(res) <- 1:nrow(res)
res <- res[order(res$extract_method), ]
We can get a few insights from the results res
. For example, we can loow were is.()
does not return same as inherits()
:
> res[res$inherits != res$is, ]
object extract_method extract_result inherits is is.type
6 integer vector mode numeric FALSE TRUE TRUE
87 call storage.mode language FALSE TRUE TRUE
89 call type language FALSE TRUE TRUE
Of course the results show much more, e.g. we can see where inherits()
returns FALSE
on types that where returned of one of the three extraction methods and so on. I left this out here. In fact, I think my answer is much broader since it takes into account both, differences in extraction and test of object type. After reading quite some time about object types I arrived at the code above and wanted to share it. However, using res[res$inherits != res$is, ]
soly answers the question.