Using the class
function allows us to determine the class of an object:
> x = 5
> class(x)
[1] "numeric"
I also understand that we can use the is.object
command to determine if an object has a class. However some object types are implicit, that is
> is.object(x)
[1] FALSE
Would it be correct to state that all variables in R are objects and is.object
is a test for non-implicit classes only?
Also, how do types fit into this. Naively, I thought that the following piece of code would produce an error:
> x = 5
> class(x) = "fake"
> x = X + 1
> x + 1
[1] 6
attr(,"class")
[1] "fake"
But x
still has type "double", still everything still works. Can types be thought of as a superclass that all other objects inherit from?
typeof
returns the type of internal C representation, and it is not used for method dispatch. So strictly speaking you can not think of types as "superclasses".
There are instead basic classes (numeric, character, list, function etc) which roughly correspond to the names
returned by typeof
, but not always (for example type double is of class numeric, special and closure are of class
function, and class data.frame is of type list!).
With S3 and S4 systems you can build non trivial classes using basic classes (but not necessary extending one of those!! example: setClass("foo", list(a="numeric",b="character")
does not extend any of the basic classes).
For objects from these basic classes is.object
returns FALSE
. As its documentation says, this function provides
a very fast way to check if the object is of user build S3 or S4 class (i.e. not one of basic classes).
After casting x
as "fake" your object is formally not of "numeric" class:
is(x, "numeric")
#FALSE
but it is interpretable as basic "numeric" object:
is.numeric(x)
#TRUE
And this is why +
works here. So, internally, as @Richie already said the default method interprets x
as of
numeric basic class.
This conceptual mess is because of S3 informal treatment of classes. Use S4 instead.
correspondence between typeof(.) and basic 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"
A partial answer to the first question is found in Chapter 2 of the R language defninition
R does not provide direct access to the computer’s memory but rather provides a number of specialized data structures we will refer to as objects. These objects are referred to through symbols or variables. In R, however, the symbols are themselves objects and can be manipulated in the same way as any other object.
So, yes, all variables are objects.
is.object
seems to be more or less equivalent to function(x) !is.null(attr(x, "class"))
but I'm willing to be proved wrong on that.
As for the second question, I think this is what happens:
Since x
has class "fake", R looks for a method +.fake
in the addition but when it doesn't find one, it resorts to the default method. That default method is based upon underlying C code, which uses typeof(x)
(or a C equivalent) to determine what should be done. In this case the type of x
is "integer".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With