Importing methods
flying-sheep opened this issue · 6 comments
Hi!
I’m a fan of https://github.com/thomasp85/patchwork
It defines functions like -.ggplot
which I’d like to import. I need to use import:::from
for this, which seems unintuitive: when the patchwork package is attached, I can use those functions, so why would I need to use private accession syntax?
It's because they're not exported (https://github.com/thomasp85/patchwork/blob/master/NAMESPACE). S3methods are a bit special like that. Not sure exactly why that is. import
deliberately makes it different when you want to import non-exported things. Not sure how to handle s3methods.. interesting.
get(".__NAMESPACE__.", envir=asNamespace("patchwork"))[["S3methods"]]
reveals the available methods, whereas
ls(get(".__S3MethodsTable__.", envir=asNamespace("patchwork")))
does not.
Perhaps S3 deserves their own function import::S3from(...)
which could check the S3methods
entry in the namespace to validate the import call, and then internally do the :::
call.
Not sure what the nice syntax would be, verbose to include the .class
suffix for each import or allow this to be specified for all with a single parameter, say
import::S3from(pkg, "-", "*", "&", .for = classname)
But then what should happen when you want to import for multiple classnames in one call.
Maybe it's ok then to require several calls.
This did not make it into the 1.2.0 release. I'm not sure about the cost-benefit ratio of adding this feature given that it seems to be work-aroundable with one extra :
if I understand it correctly. I suggest we put this on ice unless a stronger rationale emerges for fixing this (even better if such a rationale were accompanied with a nice PR of course 😃).
I just find about this issue.
I wrote a new method for a base generic functions and as everything else, I just did `import::from("src/code.r", "generic.class").
To my surprise, when calling generic(object)
, the generic.class
was not dispatched, despite generic.class(object)
could be called directly.
Changing from import::from
to import::here
does fix the issue. Although it's also importing the code directly, which I am not sure I am happy about.
This seems related, but still separate, from the original issue. I fiddled around with it and confirmed that this is the case, based on a small S3 class, catter
that cats instead of printing
# module_catter.R
catter <- function(x) {
class(x) <- "catter"
x
}
print.catter <- function(x) {
cat(x)
invisible(x)
}
And then run the following
import::from(module_catter.R, catter)
x <- catter(letters[1:3]) # Construct catter
x # Uses default print()
#> [1] "a" "b" "c"
#> attr(,"class")
#> [1] "catter"
import::from(module_catter.R, print.catter)
x |> print.catter() # Works correctly
#> a b c
x # print.catter() not used :-(
#> [1] "a" "b" "c"
#> attr(,"class")
#> [1] "catter"
import::here(module_catter.R, print.catter)
x # print.catter() used
#> a b c
But that doesn't explain why the method is not correctly dispatched. The print.catter()
function is on the search path (in the imports
environment position on the search path), but S3 dispatch is not looking there. Why this is so, I have no idea. Does library()
do something else to register a method. Something to do with namespaces (loadedNamespaces()
) perhaps? And if so, is the Global Environment handled in a special manner?