I know I can list all S3 methods for a particular generic function, say summary
, by
.S3methods("summary")
# [1] summary.aov summary.aovlist*
# [3] summary.aspell* summary.check_packages_in_dir*
# [5] summary.connection summary.data.frame
# [7] summary.Date summary.default
# [9] summary.ecdf* summary.factor
#[11] summary.glm summary.infl*
#[13] summary.lm summary.loess*
#[15] summary.manova summary.matrix
#[17] summary.mlm* summary.nls*
#[19] summary.packageStatus* summary.PDF_Dictionary*
#[21] summary.PDF_Stream* summary.POSIXct
#[23] summary.POSIXlt summary.ppr*
#[25] summary.prcomp* summary.princomp*
#[27] summary.proc_time summary.srcfile
#[29] summary.srcref summary.stepfun
#[31] summary.stl* summary.table
#[33] summary.tukeysmooth*
However, I know that some of these functions come from stats
, while some from base
. If I load more packages into R this list can be much longer. I therefore want to restrict the search in a particular package / namespace, but I don't find a way to do this.
The manual of ?.S3methods
appears to be self-contradicted.
.S3methods(generic.function, class, envir=parent.frame())
envir: the environment in which to look for the definition of the
generic function, when the generic function is passed as a
character string.
So I tried the following but still get all methods displayed:
.S3methods("summary", envir = getNamespace("base"))
In "Details" section of the manual, it is said:
‘methods()’ finds S3 and S4 methods associated with either the ’generic.function’ or ‘class’ argument. Methods are found in all packages on the current ‘search()’ path. ‘.S3methods()’ finds only S3 methods, ‘.S4methods()’ finds only only S4 methods.
So basically it denies the use of argument envir
.
Is there anyway I can achieve a restricted search and display.
S3 implements a style of object oriented programming called generic-function OO. This is different to most programming languages, like Java, C++ and C#, which implement message-passing OO. In message-passing style, messages (methods) are sent to objects and the object determines which function to call.
A generic function is one which may be applied to different types of inputs producing results depending on the type of input. Examples are plot() and summary() We demonstrate these differences using sample data from. Dalgaard's Introductory Statistics with R.
An S3 class is the most prevalent and used class in R programming. It is easy to implement this class and most of the predefined classes are of this type. An S3 object is basically a list with its class attributes assigned some names. And the member variable of the object created is the components of the list.
A constructor is a special method that's executed whenever you create a new object of the class. So, each time you run d <- Dog$new() , a new instance of the Dog class is created, and therefore, the constructor method is executed. In R and R6, the constructor is defined with the initialize function.
MrFlick's answer (now unfortunately deleted) is very helpful. It is my fault to have forgotten to check the returned values of .S3methods
. However, his answer does not completely resolve the matter.
xx <- .S3methods("summary")
yy <- attr(xx, "info")
levels(yy$from)
#[1] "base" "datasets"
#[3] ".GlobalEnv" "graphics"
#[5] "grDevices" "methods"
#[7] "stats" "utils"
#[9] "registered S3method for summary"
The level "registered S3method for summary" is rather ambiguous. With this approach, only 5 results from stats
package can be displayed:
xx[yy$from == "stats"]
#[1] "summary.aov" "summary.glm" "summary.lm" "summary.manova"
#[5] "summary.stepfun"
Just after my posting this question, I realized that there is one way via regex. And this reveals that in fact there are 16 hits.
grep("^summary.", ls(getNamespace("stats")), value = TRUE)
# [1] "summary.aov" "summary.aovlist" "summary.ecdf"
# [4] "summary.glm" "summary.infl" "summary.lm"
# [7] "summary.loess" "summary.manova" "summary.mlm"
#[10] "summary.nls" "summary.ppr" "summary.prcomp"
#[13] "summary.princomp" "summary.stepfun" "summary.stl"
#[16] "summary.tukeysmooth"
So before any alternative solution is found, I would stay with using regex. Here is a function.
## provide (generic) function name and package name as strings
findS3Fun <- function (Fun, pkg) {
all_fun <- ls(getNamespace(pkg))
all_fun[startsWith(all_fun, sprintf("%s.", Fun))]
}
findS3Fun("summary", "stats")
findS3Fun
is actually buggy.
findS3Fun("seq", "base")
#[1] "seq.Date" "seq.default" "seq.int" "seq.POSIXt"
findS3Fun("sort", "base")
#[1] "sort.default" "sort.int" "sort.list" "sort.POSIXlt"
seq.int
is not the "int" method for seq
. Neither sort.int
nor sort.list
is the "int" or "list" method for sort
. They are just stand alone functions with .
in their function name.
.S3methods("seq")
#[1] seq.Date seq.default seq.POSIXt
.S3methods("sort")
#[1] sort.bibentry* sort.default sort.POSIXlt
## this function is from package `utils` not `base`
environment(getS3method("sort", "bibentry"))
#<environment: namespace:utils>
So the safest approach is probably still to work with the returned values of .S3methods
.
getAnywhere
(getS3method
)Back to the example with "summary". Functions that are not exported from namespaces, i.e., those with yy$visible = FALSE
, have yy$from = "registered S3method for summary"
.
with(yy, from[!visible])
# [1] registered S3method for summary registered S3method for summary
# [3] registered S3method for summary registered S3method for summary
# [5] registered S3method for summary registered S3method for summary
# [7] registered S3method for summary registered S3method for summary
# [9] registered S3method for summary registered S3method for summary
#[11] registered S3method for summary registered S3method for summary
#[13] registered S3method for summary registered S3method for summary
#[15] registered S3method for summary registered S3method for summary
#8 Levels: base datasets graphics grDevices methods stats ... registered S3method for summary
However, since we know the names of these functions, why not apply getAnywhere
on them?
zz <- lapply(xx[!yy$visible], getAnywhere)
Then the package / namespace information can be extracted from zz
with some effort. However, this lapply
+ getAnywhere
is quite slow. Since getAnywhere
returns more things than I needed, I dug into its source code to see whether I could do some trimming. It turns out that I can.
hidden <- xx[!yy$visible]
# [1] "summary.aovlist" "summary.aspell"
# [3] "summary.check_packages_in_dir" "summary.ecdf"
# [5] "summary.infl" "summary.loess"
# [7] "summary.mlm" "summary.nls"
# [9] "summary.packageStatus" "summary.PDF_Dictionary"
#[11] "summary.PDF_Stream" "summary.ppr"
#[13] "summary.prcomp" "summary.princomp"
#[15] "summary.stl" "summary.tukeysmooth"
CLASS <- substr(hidden, nchar("summary") + 2L, nchar(hidden))
#[1] "aovlist" "aspell" "check_packages_in_dir"
# [4] "ecdf" "infl" "loess"
# [7] "mlm" "nls" "packageStatus"
#[10] "PDF_Dictionary" "PDF_Stream" "ppr"
#[13] "prcomp" "princomp" "stl"
#[16] "tukeysmooth"
vapply(CLASS,
function (u) getNamespaceName(environment(getS3method("summary", u)))[[1L]],
"", USE.NAMES = FALSE)
# [1] "stats" "utils" "tools" "stats" "stats" "stats" "stats" "stats" "utils"
#[10] "tools" "tools" "stats" "stats" "stats" "stats" "stats"
Now let me wrap up these ideas into a function.
findS3Fun <- function (Fun, pkg) {
xx <- .S3methods(Fun)
yy <- attr(xx, "info")[1:2]
where <- yy[[2L]] ## yy$from
where <- levels(where)[where] ## factor to character
hidden <- !yy[[1L]] ## !yy$visible
hidden_xx <- xx[hidden] ## hidden functions
if (length(hidden) > 0L) {
CLASS <- substr(hidden_xx, nchar(Fun) + 2L, nchar(hidden_xx))
aux <- function (u) getNamespaceName(environment(getS3method(Fun, u)))[[1L]]
where[hidden] <- vapply(CLASS, aux, "", USE.NAMES = FALSE)
}
export <- where == pkg
xx <- xx[export]
visible <- yy[[1L]][export]
## use "regex" to find functions with "." in their names but not methods
all_fun <- ls(getNamespace(pkg))
all_fun <- all_fun[startsWith(all_fun, sprintf("%s.", Fun))]
misc <- all_fun[!(all_fun %in% xx)]
## return functions by category
list(visible = xx[visible], invisible = xx[!visible], misc = misc)
}
In the end I still use regex to catch functions with .
in their names but are not rightful methods. They are classified as "misc", besides "visible" and "invisible".
findS3Fun("summary", "stats")
#$visible
#[1] "summary.aov" "summary.glm" "summary.lm" "summary.manova"
#[5] "summary.stepfun"
#
#$invisible
# [1] "summary.aovlist" "summary.ecdf" "summary.infl"
# [4] "summary.loess" "summary.mlm" "summary.nls"
# [7] "summary.ppr" "summary.prcomp" "summary.princomp"
#[10] "summary.stl" "summary.tukeysmooth"
#
#$misc
#character(0)
findS3Fun("sort", "base")
#$visible
#[1] "sort.default" "sort.POSIXlt"
#
#$invisible
#character(0)
#
#$misc
#[1] "sort.int" "sort.list"
findS3Fun("[", "base")
#$visible
# [1] "[.AsIs" "[.data.frame" "[.Date"
# [4] "[.difftime" "[.Dlist" "[.factor"
# [7] "[.hexmode" "[.listof" "[.noquote"
#[10] "[.numeric_version" "[.octmode" "[.POSIXct"
#[13] "[.POSIXlt" "[.simple.list" "[.table"
#[16] "[.warnings"
#
#$invisible
#character(0)
#
#$misc
#character(0)
findS3Fun("[[", "base")
#$visible
#[1] "[[.data.frame" "[[.Date" "[[.factor"
#[4] "[[.numeric_version" "[[.POSIXct"
#
#$invisible
#character(0)
#
#$misc
#character(0)
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