rticulate/import

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?

Discussion of this issue was migrated to #58 which is now in dev, so closing this issue as duplicate.