Skip to content

fixes for S4 generics and classes defined across packages#663

Open
lawremi wants to merge 3 commits into
mainfrom
x-package-s4-fixes
Open

fixes for S4 generics and classes defined across packages#663
lawremi wants to merge 3 commits into
mainfrom
x-package-s4-fixes

Conversation

@lawremi
Copy link
Copy Markdown
Collaborator

@lawremi lawremi commented May 28, 2026

This contains two fixes:

  1. The current code assumes that generic@package indicates the home package of the generic. Unfortunately, that is not the case in general. The methods package uses @package to refer to the package defining the original function that the generic represents. Thus, setGeneric("nrow", ...) in a package will create a generic where @package == "base". To make matters worse, topenv(environment(generic)) is the namespace of @package, so the only way to find the package defining the generic is a brute force search through namespace imports.
  2. Much easier, I noticed that the S4 method registration path was not passing along the calling environment to the getClass() call to resolve S7 old classes, even though that seemed to be the intent. Omitting where might problem if a parent package registers those classes with S4.

lawremi added 3 commits May 28, 2026 16:02
… existing functions generic, generic@package is the package of the original function
@hadley
Copy link
Copy Markdown
Member

hadley commented May 30, 2026

BTW I'm happy to review any of your PRs, but I've been waiting for you to explicitly request a review.

@lawremi lawremi requested a review from hadley June 1, 2026 08:03
Comment thread R/S4.R
}

S4_package_name <- function(f, env) {
if (methods::getPackageName(topenv(env)) == f@package) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need create = FALSE here? (for safety)

Comment thread R/S4.R
find_package_with_symbol <- function(name, env, exclude = NULL) {
imports <- getNamespaceImports(topenv(env))
pkgs <- setdiff(names(imports), exclude)
Find(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO I think this would be a little easier to understand if it used a for loop with an early return when the object was found, and then the error message from above could move into this function.

Comment thread R/S4.R

# generic was defined for a function from a different package, like base
find_package_with_symbol(name, env, exclude = f@package) %||%
stop(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth switching to use stop2() and sprintf() for consistency with other errors in this package.

Comment thread R/S4.R
return(f@package)
}

name <- as.vector(f@generic)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be as.character()? But I don't know what f@generic would be otherwise.

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

Successfully merging this pull request may close these issues.

2 participants