Accessing classes from a specific package
getClass()
new() accepts a classRepresentation object, which you can retrieve using getClass. For example, new(getClass('className', where='packageName')). However, note that this won't work if you haven't imported the package yet, and also you have defined a new class with the same name. I demonstrate this issue here:
install.packages('lookupTable')
setClass('lookupTable', slots = c(notworking='numeric'))
new(getClass('lookupTable', where='lookupTable'))
#> An object of class "lookupTable"
#> Slot "notworking":
#> numeric(0)
(it has printed the "notworking" slot, which means it is instantiating my custom class, not the correct package version)
new(classNameWithAttribute)
There's an odd but documented feature of new, which allows you to set the package attribute on the class name, which actually works perfectly (ie doesn't have the issue mentioned above), if a bit verbosely:
name = 'className'
attr(name, 'package') = 'packageName'
new(name)
There's no reason you couldn't make this into a re-usable function though:
new = function(cls, pkg, ...){
attr(cls, 'package') = pkg
methods::new(cls, ...)
}
new('className', 'packageName')
Good Package Design
Of course, all of this can be avoided if the packagers of the S4 classes provide one of two mechanisms:
Exporting the setClass() value
setClass() has both a side effect (storing the class in the registry), and a return value (a class generator function). So if the packager chooses to store and export the return value in their NAMESPACE, we can access it later:
# In package "myPackage"
myClass = setClass('myClass')
# In package's NAMESPACE
export(myClass)
# In user's script
new(myPackage::myClass)
For example, you can test this out with the same test package from before:
install.packages('lookupTable')
new(lookupTable::lookupTable)
Exporting a constructor function
This is the standard practise in bioconductor. They define a constructor function that has the same name as the class itself. You can then access the constructor function using ::, and call it instead of new:
install.packages("BiocManager")
BiocManager::install("IRanges")
new("IRanges")
# Equivalent to
IRanges::IRanges()