[Rd] strange behavior in 'inherits' check for loaded S4 object

Kevin Ushey kevinushey at gmail.com
Sat Jun 25 21:46:24 CEST 2016


Hi,

(sorry for the wall of text; the issue here appears to be rather complicated)

I'm seeing a somewhat strange case where checking whether an S4 object
inherits from a parent class defined from another package with
'inherits' fails if that object is materialized through a call to
'load'. That's a mouthful, so I've put together a relatively small
reproducible example online here:

https://github.com/kevinushey/s4inherits

This package, 's4inherits', defines an S4 class, 'SubMatrix', that
inherits from the 'dsyMatrix' class defined in the Matrix package.
After installing the package, I run some simple tests:

$ R -f test-save.R

> library(s4inherits)
> data <- SubMatrix(1)
>
> is(data, "SubMatrix")
[1] TRUE
> inherits(data, "SubMatrix")
[1] TRUE
>
> is(data, "dsyMatrix")
[1] TRUE
> inherits(data, "dsyMatrix")
[1] TRUE
>
> save(data, file = "test.RData")
>

All the inheritance checks report as we would expect. I check that the
inheritance reports are as expected, then save that object to
'test.RData'. I then load that data file in a new R session and run
the same checks:

$ R -f test-load.R

> library(methods)
> load("test.RData")
>
> inherits(data, "SubMatrix")
Loading required package: s4inherits
[1] TRUE
> is(data, "SubMatrix")
[1] TRUE
>
> inherits(data, "dsyMatrix")
[1] FALSE # (??)
> is(data, "dsyMatrix")
[1] TRUE
>

Note that R now reports that my loaded object does _not_ inherit from
"dsyMatrix", yet this occurs only when checked with 'inherits()' --
'is' produces the expected result.

I do not see the behavior if I explicitly load / attach the
's4inherits' package before loading the associated data file; it only
occurs if the package namespace is loaded in response to loading the
data object hosting a 'SubMatrix' object.

More precisely, the package namespace is loaded when the promise
hosting the data object is evaluated; that promise being generated by
'load', if I understand correctly. Somehow, evaluation of that promise
within the call to 'inherits' in this very special case causes the
unexpected behavior -- ie, if the first thing that you do with the
loaded object is check its class with 'inherits', then you get this
unexpected result.

Even more, this behavior seems to go away if the 's4inherits' package
explicitly exports the class -- however, you could imagine this class
normally being internal to the package, and so it may be undesirable
to export it.

I checked a bit into the C code, and IIUC the check here looks up the
class hierarchy in the R_S4_extends_table object defined in
'attrib.c', so it seems like that mapping is potentially not getting
constructed with the full hierarchy (although hopefully someone with
more knowledge of the S4 internals + interaction with S3 can
elaborate).

(FWIW, this was distilled from a case where S3 dispatch on a similar
loaded S4 object failed, due to failure to resolve the class hierarchy
for the S3 dispatch context.)

Thanks,
Kevin

---

$ R --slave -e "utils::sessionInfo()"
R Under development (unstable) (2016-06-13 r70769)
Platform: x86_64-apple-darwin15.5.0 (64-bit)
Running under: OS X 10.11.5 (El Capitan)



More information about the R-devel mailing list