Reputation: 8494
In a package, I would like to call an S3 method "compact" for object foobar
.
There would therefore be a compact.foobar
function in my package, along with the compact
function itself:
compact = function(x, ...){
UseMethod("compact", x)
}
However, this latter would be conflicting with purrr::compact
.
I could default the method to use purrr
(compact.default = purrr::compact
, or maybe
compact.list = purrr::compact
), but that would make little sense if the user does not have purrr
loaded.
How can I default my method to the loaded version of compact
, in the user environment? (so that it uses purrr::compact
, any other declared compact
function, or fails of missing function)
Upvotes: 2
Views: 157
Reputation: 545588
Unfortunately S3 does not deal with this situation well. You have to search for suitable functions manually. The following works, more or less:
get_defined_function = function (name) {
matches = getAnywhere(name)
# Filter out invisible objects and duplicates
objs = matches$objs[matches$visible & ! matches$dups]
# Filter out non-function objects
funs = objs[vapply(objs, is.function, logical(1L))]
# Filter out function defined in own package.
envs = lapply(funs, environment)
funs = funs[! vapply(envs, identical, logical(1L), topenv())]
funs[1L][[1L]] # Return `NULL` if no function exists.
}
compact.default = function (...) {
# Maybe add error handling for functions not found.
get_defined_function('compact')(...)
}
This uses getAnywhere
to find all objects named compact
that R knows about. It then filters out those that are not visible because they’re not inside attached packages, and those that are duplicate (this is probably redundant, but we do it anyway).
Next, it filters out anything that’s not a function. And finally it filters out the compact
S3 generic that our own package defines. To do this, it compares each function’s environment to the package environment (given by topenv()
).
This should work, but it has no rule for which function to prefer if there are multiple functions with the same name defined in different locations (it just picks an arbitrary one first), and it also doesn’t check whether the function signature matches (doing this is hard in R, since function calling and parameter matching is very flexible).
Upvotes: 1