Similar to the post on this topic for S4 classes, I am wondering about the resolution method and the conflict prevention for S3 classes.
Let me show an example. I created two packages: pkga and pkgb. Both happen to have an S3 class constructor function returning an object whose class has the same name myclass
#' @export
myclass_instance <- function() {
structure(list(name = "pkga"), class = c("myclass"))
}
#' @export
whatever <- function(obj) {
UseMethod("whatever", obj)
}
#' @export
whatever.default <- function(obj) {
print("pkga::whatever.default")
}
#' @export
whatever.myclass <- function(obj) {
print("pkga::whatever.myclass")
}
and for pkgb
#' @export
myclass_instance <- function() {
structure(list(name = "pkgb"), class = c("myclass"))
}
#' @export
whatever <- function(obj) {
UseMethod("whatever", obj)
}
#' @export
whatever.default <- function(obj) {
print("pkgb::whatever.default")
}
#' @export
whatever.myclass <- function(obj) {
print("pkgb::whatever.myclass")
}
Now, if I have both packages installed, and try the following:
> aobj<-pkga::myclass_instance()
> pkga::whatever(aobj)
[1] "pkga::whatever.myclass"
> pkga::whatever(3)
[1] "pkga::whatever.default"
This is all correct. However, if I create an object from pkgb, and then pass it to pkga::whatever
it will not apply the default as I would expect (they are two completely unrelated classes that happen to have the same name), because the resolution is only made on the name
> bobj<-pkgb::myclass_instance()
> pkga::whatever(bobj)
[1] "pkga::whatever.myclass"
This can give strange effects if two unrelated libraries happen to have the same class name, and the generic name happen to conflict. While a rare and unlikely occurrence, from the formal point of view I don't like it one bit, so I was wondering if there's a way to prevent this from happening that is better than prefixing the class name with the package name, e.g.
#' @export
myclass_instance <- function() {
structure(list(name = "pkga"), class = c("pkga::myclass"))
}
#' @export
whatever <- function(obj) {
UseMethod("whatever", obj)
}
#' @export
whatever.default <- function(obj) {
print("pkga::whatever.default")
}
#' @export
`whatever.pkga::myclass` <- function(obj) {
print("pkga::whatever.myclass")
}
and similar for pkgb.