Skip to content

load_all() does not activate S4 dispatch for methods on ...-dispatching base generics (e.g. seq) #340

Description

@programLyrique

Context

I develop a mutation testing package for R (mutator) and it uses pkgload to quickly reload the package for each of the test suite runs it has to perform (can be 1000s of them). I have system tests that compare results between running a test suite with pkgload or running it with R CMD INSTALL (so installing the package each time) and they caught a discrepancy for package nanotime (0.3.15) on S4 dispatches.

Its tinytest suite calls seq(<nanoival>, by = <nanoperiod>, length.out = ...), which under load_all() falls to seq.default and then hits nanotime's deliberately-disabled + for those types:

binary '+' is not defined for 'nanoival' and 'nanoperiod' objects; instead use 'plus(e1, e2, tz)'

Summary

When a package defines an S4 method on a base generic that dispatches on ... (the clearest example is seq, whose implicit generic has signature "..."), the method is registered correctly under pkgload::load_all() (existsMethod() / selectMethod() find it and it runs when invoked directly), but normal dispatch does not reach it as soon as the call has more than one argument. R silently falls through to the internal default (seq.default).

The exact same package installed (R CMD INSTALL + library()) dispatches correctly for any number of arguments. Hence, a load_all()/methods setup issue, not a problem with the package.

  • seq(x) (single argument): S4 method is dispatched
  • seq(x, by = 1L, length.out = 3) (extra args): falls to seq.default (only under load_all())

Minimal reprex

# Build a tiny package: one S4 class with an S4 method on `seq`.
d <- file.path(tempfile("s4seq_"), "s4seqpkg")
dir.create(file.path(d, "R"), recursive = TRUE)
writeLines(
  "Package: s4seqpkg\nVersion: 0.1.0\nTitle: T\nDescription: d.\nAuthor: A\nLicense: MIT\nImports: methods",
  file.path(d, "DESCRIPTION")
)
writeLines(
  c("import(methods)", "exportClasses(myc)", "exportMethods(seq)"),
  file.path(d, "NAMESPACE")
)
writeLines(
  c(
    "setClass('myc', contains = 'numeric')",
    "setMethod('seq', 'myc', function(from, ...) 99L)"
  ),
  file.path(d, "R", "x.R")
)

## --- via pkgload::load_all() ---------------------------------------------
pkgload::load_all(d, quiet = TRUE)
b <- new("myc", 1)

seq(b)                              #> [1] 99      (S4 method dispatched)
seq(b, by = 1L, length.out = 3)    #> [1] 1 2 3   (WRONG: seq.default, S4 method skipped)

# The method IS registered and works when invoked explicitly:
existsMethod("seq", "myc")                                  #> [1] TRUE
selectMethod("seq", "myc")(b, by = 1L, length.out = 3)     #> [1] 99

Now the same package installed dispatches correctly:

lib <- tempfile("lib_"); dir.create(lib)
system2(file.path(R.home("bin"), "R"),
        c("CMD", "INSTALL", paste0("--library=", lib), d),
        stdout = FALSE, stderr = FALSE)

# In a fresh session:
.libPaths(c(lib, .libPaths()))
library(s4seqpkg)
b <- new("myc", 1)
seq(b)                             #> [1] 99
seq(b, by = 1L, length.out = 3)    #> [1] 99   (correct: S4 method dispatched)

Some notes

  • The method is present after load_all(): isGeneric("seq") is TRUE, existsMethod("seq", "myc") is TRUE, find("seq") shows the package's
    standardGeneric ahead of base, and selectMethod(...)() returns the right answer. Only implicit dispatch through a bare seq(...) call misses it, and only once extra arguments are present.
  • It is specific to generics that dispatch on .... S4 methods on generics that dispatch on a named formal work fine under load_all() , for instance, setMethod("mean", "myc", ...) (mean(x, ...)) dispatches correctly.
  • It is not about primitives: S4 methods on primitive group generics such as +/Arith dispatch correctly under load_all() (C-level dispatch). This rather happens with internal generics such as seq (function (...) UseMethod("seq")).
  • Not fixed by any of: methods::cacheMetaData(ns, TRUE), methods::setGeneric("seq"), or load_all(export_all = FALSE).

Environment

  • pkgload 1.5.3
  • R 4.6.1 (2026-06-24)
  • Platform: Linux (x86_64)
  • methods (base)

Related issues

Might be related to #45

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions