Reputation: 99408
From Extending R by Chamber, I heard that everything existing in R is an object (which is also true in Python: a class in Python is an object, the class of a class is a metaclass.). Is a S4 class an object? What is the type of a S4 class?
> setClass("Person",
+ slots = c(
+ name = "character",
+ age = "numeric"
+ )
+ )
> typeof(Person)
Error in typeof(Person) : object 'Person' not found
> typeof("Person")
[1] "character"
> attributes(Person)
Error: object 'Person' not found
Thanks.
Upvotes: 2
Views: 588
Reputation: 1
When defining a S4 class through setClass()
, an object of class classRepresentation
is created (ironically classRepresentation
is itself a S4 class). This object defines the class and is used when an instance of the class is created through new()
. At the user level, this classRepresentation
is usually invisible as it is stored in the namespace of the package which defines it or in a cached class table (methods:::.classTable
). Still, a user may obtain the definition through getClassDef()
.
Some answers point out that setClass()
returns a classGeneratorFunction
. However the returned classGeneratorFunction
is not what defines the class. In fact, when defining S4 classes it is a common practise to ignore the return value of setClass()
and instead write a custom class constructor function through new()
. Here is an example:
setClass("Person",
slots = c(
name = "character",
age = "numeric"
)
)
# This ensures that every instance of Person is
# always initialized with a name and an age
Person <- function(name, age) {
new("Person", name=name, age=age)
}
aPerson <- Person("John", 50)
> str(aPerson)
Formal class 'Person' [package ".GlobalEnv"] with 2 slots
..@ name: chr "John"
..@ age : num 50
# Get the class definition itself
PersonDef <- getClassDef("Person")
> str(PersonDef)
Formal class 'classRepresentation' [package "methods"] with 11 slots
..@ slots :List of 2
.. ..$ name: chr "character"
.. .. ..- attr(*, "package")= chr "methods"
.. ..$ age : chr "numeric"
.. .. ..- attr(*, "package")= chr "methods"
..@ contains : list()
..@ virtual : logi FALSE
..@ prototype :Formal class 'S4' [package ""] with 0 slots
list()
.. .. ..$ name: chr(0)
.. .. ..$ age : num(0)
..@ validity : NULL
..@ access : list()
..@ className : chr "Person"
.. ..- attr(*, "package")= chr ".GlobalEnv"
..@ package : chr ".GlobalEnv"
..@ subclasses: list()
..@ versionKey:<externalptr>
..@ sealed : logi FALSE
Upvotes: 0
Reputation: 6956
As far as I know, everything in R is an object, yet classes themselves are not directly objects.
We can do object oriented programming in R. In fact, everything in R is an object. An object is a data structure having some attributes and methods which act on its attributes. Class is a blueprint for the object. We can think of class like a sketch (prototype) of a house. It contains all the details about the floors, doors, windows etc. Based on these descriptions we build the house.
(From here).
Think about S3 objects. You never really assign them, you just define a method that works for this specific class:
summary.mnist <- function(x) print("HELLO!")
x <- 3
class(x) <- "mnist"
summary(x)
# [1] "HELLO!"
typeof(mnist)
# Error in typeof(mnist) : object 'mnist' not found
Nevertheless, when working with S4, to use a Class you usually define a generator function via setClass
. This generator function then is an object of type closure, yet the class itself is not an object:
Person <- setClass("Person",
slots = c(
name = "character",
age = "numeric"
)
)
typeof(Person)
# [1] "closure"
myPerson <- Person()
typeof(myPerson)
# [1] "S4"
Upvotes: 1
Reputation: 10855
Another way of looking at this problem is that the object returned by setClass()
is an object of class classGeneratorFunction
. It's definitely an object. Also, since functions in R are also considered objects, it's an object.
We'll illustrate by adjusting the code from the original post.
personGenerator <- setClass("Person",
slots = c(name = "character",
age = "numeric"))
aPerson <- personGenerator()
At this point, we have a class generator function that generates objects of type Person
, and an instance of Person
.
We can see this with the str()
function.
str(aPerson)
> str(aPerson)
Formal class 'Person' [package ".GlobalEnv"] with 2 slots
..@ name: chr(0)
..@ age : num(0)
Similarly, we can print the structure of the personGenerator()
function.
> str(personGenerator)
Formal class 'classGeneratorFunction' [package "methods"] with 3 slots
..@ .Data :function (...)
..@ className: chr "Person"
.. ..- attr(*, "package")= chr ".GlobalEnv"
..@ package : chr ".GlobalEnv"
>
Going back to the Chambers quote, it's recounted in Hadley Wickham's Advanced R as:
To understand computations in R, two slogans are helpful.
-- Everything that exists is an object
-- Everything that happens is a function call
John Chambers quoted in Advanced R, p. 79.
Since the original question was a bit ambiguous, if "S4 class" refers to the thing represented by the return value of setClass()
, an object of type classGeneratorFunction
, this is indeed an object. However, if the "S4 class" in the original question refers to the content in the arguments of setClass()
, the thing representing Person
is not an object until code instantiates it as illustrated above with the personGenerator()
function.
Upvotes: 1