I agree that the type system in R is rather weird. The reason for it being that way is that it has evolved over (a long) time…
Note that you missed one more type-like function, storage.mode
, and one more class-like function, oldClass
.
So, mode
and storage.mode
are the old-style types (where storage.mode
is more accurate), and typeof
is the newer, even more accurate version.
mode(3L) # numeric
storage.mode(3L) # integer
storage.mode(`identical`) # function
storage.mode(`if`) # function
typeof(`identical`) # closure
typeof(`if`) # special
Then class
is a whole different story. class
is mostly just the class
attribute of an object (that’s exactly what oldClass
returns). But when the class attribute is not set, the class
function makes up a class from the object type and the dim attribute.
oldClass(3L) # NULL
class(3L) # integer
class(structure(3L, dim=1)) # array
class(structure(3L, dim=c(1,1))) # matrix
class(list()) # list
class(structure(list(1), dim=1)) # array
class(structure(list(1), dim=c(1,1))) # matrix
class(structure(list(1), dim=1, class="foo")) # foo
Finally, the class can return more than one string, but only if the class attribute is like that. The first string value is then kind of the main class, and the following ones are what it inherits from. The made-up classes are always of length 1.
# Here "A" inherits from "B", which inherits from "C"
class(structure(1, class=LETTERS[1:3])) # "A" "B" "C"
# an ordered factor:
class(ordered(3:1)) # "ordered" "factor"