[Rd] Disabling S4 primitive dispatch during method resolution affects namespace load actions

Ivan Krylov |kry|ov @end|ng |rom d|@root@org
Fri Sep 27 12:32:27 CEST 2024


Hello,

This problem originally surfaced as an interaction between 'brms',
'rstan' and 'Rcpp' [1]: a call to dimnames() from the 'brms' package on
an object of an S4 class owned by the 'rstan' package tried to load its
namespace. rstan:::.onLoad needs to load Rcpp modules, which uses load
actions and reference classes. Since methods:::.findInheritedMethods
temporarily disables primitive S4 dispatch [2], reference classes break
and the namespace fails to load. I have prepared a small reproduction
package [3], which will need to be installed to show the problem:

R -q -s -e "saveRDS(repro::mk_external(), 'foo.rds')"
R -q -s -e "readRDS('foo.rds')"
# Loading required package: repro
# Error: package or namespace load failed for ‘repro’ in
# .doLoadActions(where, attach):
#  error in load action .__A__.1 for package repro: bar$foo(): attempt
#  to apply non-function
# Error in .requirePackage(package) : unable to find required package
# ‘repro’
# Calls: <Anonymous> ... .findInheritedMethods -> getClass ->
# getClassDef -> .requirePackage
# Execution halted

(Here it has to be a show() call to trigger the package load, not just
dimnames().)

I have verified that the following patch prevents the failure in
loading the namespace, but which other problems could it introduce?

Index: src/library/methods/R/RClassUtils.R
===================================================================
--- src/library/methods/R/RClassUtils.R	(revision 87194)
+++ src/library/methods/R/RClassUtils.R	(working copy)
@@ -1812,6 +1812,9 @@
 
 ## real version of .requirePackage
 ..requirePackage <- function(package, mustFind = TRUE) {
+    # we may be called from .findInheritedMethods, which disables S4 primitive dispatch
+    primMethods <- .allowPrimitiveMethods(TRUE)
+    on.exit(.allowPrimitiveMethods(primMethods))
     value <- package
     if(nzchar(package)) {
         ## lookup as lightning fast as possible:

The original change to disable S4 primitive dispatch during method
resolution was done in r50609 (2009); this may be the first documented
instance of it causing a problem. The comment says "At the moment, this
is just for efficiency, but in principle it could be needed to avoid
recursive calls to findInheritedMethods."

-- 
Best regards,
Ivan

[1]
https://stat.ethz.ch/pipermail/r-package-devel/2024q3/011097.html

[2]
https://github.com/r-devel/r-svn/blob/776045d4601ed3ac7b8041e94c665bbfe9709191/src/library/methods/R/methodsTable.R#L457

[3]
https://codeberg.org/aitap/S4_vs_onLoad



More information about the R-devel mailing list