Hello, This question was asked here previously around 7 years ago (On extending class ExpressionSet), however the answer seems to have either changed or the problem I'm facing is not the same.
I am trying to write a class that extends ExpressionSet
. I keep running into the following error:
Error in checkSlotAssignment(object, name, value) :
assignment of an object of class “matrix” is not valid for slot ‘assayData’ in an object of class “ExpressionSet”; is(value, "AssayData") is not TRUE
My class is simply a thin wrapper around ExpressionSet
to give a couple additional slots and to allow me to write some specific methods that would not directly apply to an ExpressionSet
instance.
By way of the simplest example, the following seems to trigger the error:
setClass("MyExpressionSet",
contains = "ExpessionSet"
) -> MyExpressionSet
mat <- matrix(runif(100), nrow = 20, ncol =5))
# Fails:
my_instance <- MyExpressionSet(mat)
# Works:
normal_instance <- Biobase::ExpressionSet(mat)
The error you get for the above is:
Error: MyExpSet 'assayData' is class 'matrix' but should be or extend 'AssayData'
I've looked at the developer documentation about how to extend eSet
, however those recommendations, particularly in terms of the initialize
method, did not resolve my issue, e.g. naming all arguments and writing a new initialize
method that only passes relevant arguments to the ExpressionSet
initializer does not resolve the issue.
Based on the answer to the question at the above link, I understand that there are peculiarities with how the initialize
method was written for ExpressionSet
and eSet
that make it difficult to extend. I have a feeling the issue may be with the validObject
function, but I'm not sure.
Has anyone on this forum sucessfully extended eSet
or ExpressionSet
without having to include modified versions of the originally class definitions in their package? I've taken a look at (https://github.com/lgatto/MSnbase), which has several classes that extend eSet
, however they are using deprecated S4 syntax and have essentially copied large portions of the eSet,initialize
method in order to make their classes work.
Any advice on this would be very much appreciated.
Thanks!
Andrew
Session info:
R version 3.5.0 (2018-04-23)
Platform: x86_64-apple-darwin17.5.0 (64-bit)
Running under: macOS High Sierra 10.13.3
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] compiler_3.5.0 parallel_3.5.0 tools_3.5.0 yaml_2.1.19 Biobase_2.40.0
[6] BiocGenerics_0.26.0
Thanks! I guess I had assumed that since no initialize method was defined for the subclass it would pass all its arguments unchanged to the parent class initialize method, like an implicit
callNextMethod
. I need to look more intoSummarizedExperiment
and how difficult it would be to interoperate with existing code designed witheSet
derivatives in mind. A lot oflimma
code can be executed just with theexprs
matrix, so it might not be much of a problem in my use case.It does do as you say, modulo first constructing a prototype 'MyExpressionSet' object .Object. So your matrix is passed as the 'assayData' argument in the initialize signature, which is not actually what you want (assayData has been transformed by ExpressionSet() to be an environment containing the matrix). This generally illustrates the problem of initialize -- it exposes the internal structure of the class, which is really none of the user's business. The reason naming the argument exprs = mat works is because it matches the correct argument for your use case. The only way you'd know this is by closely examining the code, which is again generally not best practice.
Bioconductor has learned from at least some of its mistakes, and the SummarizedExperiment class is much better behaved in the way it works, in particular offering a 'real' constructor SummarizedExperiment() that is more than just the renamed call to new() returned by setClass().
These discussions belong on the bioc-devel mailing list.