Given an object of a S4 class that has been defined in an R package:
How can I reliably find out the package name (namespace) of the S4 object?
# Create a class in the global env
MyS4Class <- setClass("MyS4Class", slots = c(name = "character"), prototype = list(name = "unknown"))
class(MyS4Class)
# [1] "classGeneratorFunction"
# attr(,"package")
# [1] "methods"
obj <- new("MyS4Class")
class(obj)
# [1] "MyS4Class"
# attr(,"package")
# [1] ".GlobalEnv"
# Get an instance of a S4 class from a package
library(odbc)
obj2 <- odbc::odbc()
# isS4(obj2)
# [1] TRUE
class(obj2)
# [1] "OdbcDriver"
# attr(,"package")
# [1] "odbc"
It looks like the package
attribute is always filled with the namespace name but is the by accident or by design?
PS: The package name can be extracted as usual via attr(class(obj2), "package")
It is by design. From Section 1.12.1 of the R Internals Manual:
S4 objects are created via new() and thence via the C function R_do_new_object. This duplicates the prototype of the class, adds a class attribute and sets the S4 bit. All S4 class attributes should be character vectors of length one with an attribute giving (as a character string) the name of the package (or .GlobalEnv) containing the class definition.
We can be assured that the class attribute of an S4 object will have a package attribute, although it is technically possible the value of the package attribute can be incorrect. Looking at the C code for R_do_new_object
here, whenever an S4 object is created, the class attribute is set as defined in the class definition. Looking at the R code for setClass
(and the functions it calls, makeClassRepresentation
, assignClassDef
, and classGeneratorFunction
), the package attribute will always be assigned, though the default value (which is what you are after) can technically be custom specified as an argument to setClass()
; from help("setClass")
:
package: supplies an optional package name for the class, but the class attribute should be the package in which the class definition is assigned, as it is by default.
Assuming this is either specified correctly when the class is defined, or is not specified when the class is defined (in which case the defaults will provide the correct value), you should be able to reliably get the package name using class()
.