Skip to content

Consider checking @export or @exportS3method tags only for exported objects #1592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dipterix opened this issue Feb 6, 2024 · 9 comments
Closed

Comments

@dipterix
Copy link

dipterix commented Feb 6, 2024

I got errors "S3 method import_lfp.native_brainvis needs export or exportS3method tag." for internal S3 method import_lfp that is never exported.

Wonder how to solve this issue.

@olivroy
Copy link
Contributor

olivroy commented Feb 7, 2024

According to the docs :

You must register, i.e. @export, every S3 method regardless of whether or not the generic is exported. roxygen2 will warn you if you have forgotten.

but the warning should be more clear.

it should also be stated in the hadley/r-pkgs#1032 https://r-pkgs.org/dependencies-in-practice.html#imports-and-exports-related-to-s3

@dipterix
Copy link
Author

dipterix commented Feb 7, 2024

There is no item on Write an R extension states that a S3 method must be exported. Also CRAN policy https://cran.r-project.org/web/packages/policies.html does not require such behavior

In https://r-pkgs.org/dependencies-in-practice.html#imports-and-exports-related-to-s3

If your package “owns” an S3 generic and you want others to be able to use it, you should export the generic.

But I don't want others to be able to use it.

@olivroy
Copy link
Contributor

olivroy commented Feb 7, 2024

But it seems like adding @export to an S3 method registers it. It will not show in someone's search path. More discussion in #1322. (But I may be mistaken, I will let the experts sort all this, I think)

@dipterix
Copy link
Author

dipterix commented Feb 7, 2024

I think registering S3 methods allows functions like method.class to be found by the S3 generic when some users "outside" of the packages implements the S3 method. Basically registering to __S3MethodTable__.

If the S3 generic is never exported and not intended for regular users, then there is no need to register to __S3MethodTable__.

I think what's dangerous is a function registering to __S3MethodTable__ but not exported.

@gadenbuie
Copy link

From https://roxygen2.r-lib.org/articles/namespace.html#s3 (emphasis mine):

While S3 methods are regular functions with a special naming scheme, their “export” works a bit differently. S3 methods are exported only in the sense that calling the generic with the appropriate class will call the method; a user can’t directly access the method definition by typing its name. A more technically correctly term would be to say that the method is registered so that the generics can find it.

You must register, i.e. @export, every S3 method regardless of whether or not the generic is exported. roxygen2 will warn you if you have forgotten.

@dipterix
Copy link
Author

dipterix commented Mar 8, 2024

Hi @gadenbuie Thanks for the article. I have some questions for the S3 generics. I know the answer might exist somewhere, but I figured maybe it's better to ask here since you are the expert.

I wonder if the roxygen2 warnings will affect whether a package is accepted/archived on CRAN? To my knowledge, CRAN does not require S3 methods to be registered if they are intended to be internal. If not, then is there any way to suppress the roxygen2 warnings at all?

A more technically correctly term would be to say that the method is registered so that the generics can find it.

When I don't export S3 methods nor the generics, I can still call the generic function (within the package functions in the same package) with proper class, and R does not have any trouble finding the method functions. In fact, if I run your example code in globalenv, R can still resolve the S3 without issues.

I wonder what's the risk of not explicitly registering the S3 methods? I know in some cases, roxygen2 will interpret the S3 methods as package functions, hence the S3 cannot be registered with the generic correctly. However, that's when the functions are exported and intended for package users.

Thanks in advance for solving me puzzles : )

@gadenbuie
Copy link

gadenbuie commented Mar 8, 2024

To my knowledge, CRAN does not require S3 methods to be registered if they are intended to be internal.

From R 3.5.0 onwards, you should register S3 methods even if they are internal. There's some information in Kurt Hornik's S3 Method Lookup blogpost. You can also find lots of discussion about the confusion surrounding the @export directive when used on S3 methods in GitHub issues in this and other repos.

I wonder if the roxygen2 warnings will affect whether a package is accepted/archived on CRAN?

devtools::document() is something you run locally on your own machine in the process of developing your package, so those warnings are only visible to you and won't be seen on CRAN.

@dipterix
Copy link
Author

dipterix commented Mar 8, 2024

Thanks, I see:

However, all registered methods could be shadowed by GEN.CLS exports in attached packages (found on the search path ahead of the registry). To make S3 lookup both more safe and more efficient, it was changed in R 3.5.0 to use the registry after the top level environment (see ?topenv) of the calling environment. Alongside, all S3 methods in base are now registered as well.

This makes sense. If there are two implementations of S3 methods are available for the same class, then the priority could be a problem, and hence registering the method is required.

One thing that was mentioned though was that R will search the topenv of the calling evironment. If the S3 method and generics are in the same package and is only called inside of the package, that means there shouldn't be any problem for R to find the S3 method (defined within the same package) correctly.

@dipterix
Copy link
Author

dipterix commented Mar 8, 2024

Closing this issue as my questions are well addressed.

@dipterix dipterix closed this as completed Mar 8, 2024
markheckmann added a commit to markheckmann/officer that referenced this issue Sep 12, 2024
Roxygen throws warings. Export of s3 methods required. See discussion here: r-lib/roxygen2#1592
davidgohel pushed a commit to davidgohel/officer that referenced this issue Sep 14, 2024
Roxygen throws warnings. Export of s3 methods required. See discussion here: r-lib/roxygen2#1592
mpadge added a commit to ropensci/osmdata that referenced this issue Jun 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants