If we add exportClass("AffyBatch") to NAMESPACE of affy package and
reinstall,
then promptClass("AffyBatch") yields among other things

\section{Methods}{
  \describe{
    \item{MAplot}{\code{signature(object = "AffyBatch")}: ... }
    \item{Mbox}{\code{signature(object = "AffyBatch")}: ... }
    \item{[}{\code{signature(x = "AffyBatch")}: ... }
    \item{[<-}{\code{signature(x = "AffyBatch")}: ... }
    \item{bg.correct}{\code{signature(object = "AffyBatch", method =
"character")}: ... }
    \item{boxplot}{\code{signature(x = "AffyBatch")}: ... }
    \item{cdfName}{\code{signature(object = "AffyBatch")}: ... }
    \item{computeExprSet}{\code{signature(x = "AffyBatch", pmcorrect.method
= "character", summary.method = "character")}: ... }
    \item{dim}{\code{signature(x = "AffyBatch")}: ... }
    \item{hist}{\code{signature(x = "AffyBatch")}: ... }
    \item{image}{\code{signature(x = "AffyBatch")}: ... }
    \item{indexProbes}{\code{signature(object = "AffyBatch", which =
"missing")}: ... }
    \item{indexProbes}{\code{signature(object = "AffyBatch", which =
"character")}: ... }
    \item{intensity}{\code{signature(object = "AffyBatch")}: ... }
    \item{intensity<-}{\code{signature(object = "AffyBatch")}: ... }
    \item{length}{\code{signature(x = "AffyBatch")}: ... }
    \item{mas5calls}{\code{signature(object = "AffyBatch")}: ... }
    \item{mm}{\code{signature(object = "AffyBatch")}: ... }
    \item{mm<-}{\code{signature(object = "AffyBatch", value = "ANY")}: ... }
    \item{mmindex}{\code{signature(object = "AffyBatch")}: ... }
    \item{normalize.methods}{\code{signature(object = "AffyBatch")}: ... }
    \item{normalize}{\code{signature(object = "AffyBatch")}: ... }
    \item{pm}{\code{signature(object = "AffyBatch")}: ... }
    \item{pm<-}{\code{signature(object = "AffyBatch", value = "ANY")}: ... }
    \item{pmindex}{\code{signature(object = "AffyBatch")}: ... }
    \item{probeNames}{\code{signature(object = "AffyBatch")}: ... }
    \item{probes}{\code{signature(object = "AffyBatch")}: ... }
    \item{probeset}{\code{signature(object = "AffyBatch")}: ... }
         }
}

This set of methods could be taken to define the interface contract --
except that
we don't know what any of these things returns, and it seems to me that
return
value specification is a critical part of an interface infrastructure.
Perhaps
Martin's design can capture that -- it certainly seems possible to do given
recent
work on return value determination.  But this is a side issue.  Another
issue is
that the set of visible methods depends upon the searchlist at the time
discovery
is attempted.

For the motivating problem, I feel it would be better to go in another
direction.
Yes one could model AffyBatch and then create some isomorphic class on which
all
these methods succeed, though the class content is not that of an AffyBatch.
And formal methods for verifying conformance of the new class to the
AffyBatch
contract could be created.

But I prefer to look at the method and see whether we have good abstractions
for
that.  bg.correct.mas is a spatial modeling function.  I would like to see
it
implemented against a SpatialResponse class, for which things like hist,
image,
contour are naturally defined.  Then given that AffyBatch is a reasonable
container
for raw intensities from CEL files, I'd like to be able to extract a
SpatialResponse
from an AffyBatch, either by direct request or by coercion.  The new class
that James
is thinking about would also have to be able to generate a SpatialResponse
object
for application of bg.correct.mas

The methods for SpatialResponse, defined in its defining package, establish
the
interface contract (modulo return value handling).  If I extend this class
in some
way to, e.g., D, extension as defined in S4 propagates the methods from
SpatialResponse
to D.  If my definition of D entails that some SpatialResponse methods will
fail --
for example, contouring makes no sense for the responses in D -- then I am
obligated
to override the propagated method with one that throws an error.  But I
don't
need any other infrastructure to ensure that the extension obeys the
interface
defined for the base class.

I agree that both user and developer work should not be frail to
modifications of
class representation.  I question whether new infrastructure introducing
interface
contracts is going to diminish such frailties when they are present.  I also
think we will benefit from reducing use of methods like bg.correct.mas
defined
directly against a container for assay outputs.  Classes that represent
statistical
data structures should function as middle layers between containers dealing
with
proprietary data structures and statistical algorithms.  Certainly
background
correction is a sensible abstract operation against an AffyBatch from a user
perspective, but the developer and algorithm designer will probably be aided
by
ignoring details of affy data structures and dealing directly with
mathematically
motivated structures.


On Wed, Nov 26, 2008 at 11:05 AM, Martin Morgan <mtmorgan@fhcrc.org> wrote:

> Forgot to attach things...
> --
> Martin Morgan
> Computational Biology / Fred Hutchinson Cancer Research Center
> 1100 Fairview Ave. N.
> PO Box 19024 Seattle, WA 98109
>
> Location: Arnold Building M2 B169
> Phone: (206) 667-2793
>
> setClass("InterfaceRepresentation",
>         representation=representation(.slots="list"))
>
> .slots <- function(object, ...)
>    slot(object, ".slots")
>
> setValidity("InterfaceRepresentation", function(object) {
>    msg <- NULL
>    slots <- .slots(object)
>    if (length(slots)==0)
>        msg <- c(msg, "interfaces must have slots defined")
>    ok <- sapply(slots, is, "function")
>    if (!all(ok))
>        msg <- c(msg, "all slots must be functions")
>    ## FIXME: other checks
>    if (is.null(msg)) TRUE else msg
> })
>
> .InterfaceRepresentation <- function(...) {
>    new("InterfaceRepresentation", .slots=list(...))
> }
>
> .interfaces <- new.env(parent=emptyenv())
>
> setInterface <- function(interface, ...) {
>    slots <- list(...)
>    .interfaces[[interface]] <- .InterfaceRepresentation(...)
>    setClass(interface,
>             contains="Implementation",
>             representation=representation("VIRTUAL"))
>    invisible(.interfaces[[interface]])
> }
>
> ## FIXME: get, show for InterfaceRepresentation
>
> .implementationMangler <- function(class, interface, ...)
>    paste(".__I__", interface, ":", class, sep="")
>
> .implementationDemangler <- function(name, ...) {
>    parts <- strsplit(name, "[_:]")[[1]][5:6]
>    paste("implements '", parts[[1]], "' of class '", parts[[2]], "'",
>          sep="")
> }
>
> setClass("Implementation")
>
> setMethod("$", "Implementation", function(x, name) {
>    ## FIXME: enforce 'name' as member of interface
>    slot(x, name)
> })
>
> setMethod(show, "Implementation", function(object) {
>    cat("class:", .implementationDemangler(class(object)), "\n")
>    cat("interface:\n")
>    nms <- slotNames(object)
>    args <- lapply(nms, function(elt) {
>        frmls <- formals(slot(object, elt))
>        paste(names(frmls), as.character(frmls), sep="=", collapse=", ")
>    })
>    cat(paste("  ", nms, "(", args, ")\n", sep="", collapse=""))
> })
>
> setImplementation <- function(Class, interface, ...) {
>    if (!exists(interface, .interfaces))
>        stop("undefined interface '", interface, "'", sep="")
>    interfaceRepresentation <- .interfaces[[interface]]
>
>    vals <- list(...)
>    slots <- .slots(interfaceRepresentation)
>    ok <- names(vals) %in% names(slots)
>    if (!all(ok))
>        stop("unknown implementation arguments:",
>             paste(names(vals)[!ok], collapse=" "))
>    ok <- sapply(vals, is, "function")
>    if (!all(ok))
>        stop("non-function values:",
>             paste(names(vals)[!ok], collapse=" "))
>
>    slots[names(vals)] <- vals
>    cls <- lapply(slots, class)
>    representation <- do.call(representation, cls)
>    prototype <- do.call(prototype, slots)
>    implClassName <- .implementationMangler(Class, interface)
>    setClass(implClassName,
>             contains=interface,
>             representation=representation,
>             prototype=prototype)
>    setIs(Class, interface, coerce=function(from) {
>        ## yuck -- lying about what is returned
>        from
>    }, replace=function(from, value) {
>        stop("cannot use 'as<-'")
>    })
>    invisible(getClass(implClassName))
> }
>
> setGeneric("getImplementation", function(Class, interface, ...)
> {
>    standardGeneric("getImplementation")
> })
>
> setMethod(getImplementation, "character",
>    function(Class, interface, ...)
> {
>    implementationName <- .implementationMangler(Class, interface)
>    new(implementationName)
> })
>
> setMethod(getImplementation, "ANY",
>    function(Class, interface, ...)
> {
>    callGeneric(class(Class), interface, ...)
> })
>
>
> source("Interface.R")
>
> ## define an interface
> setInterface("AnInterface",
>             foo=function(x, ...) stop("not implemented"),
>             bar=function(x, y=1, ...) stop("not implemented"))
>
> ## create a class and (partially) implement the interface
> setClass("A", representation=representation(x="numeric"))
> setImplementation("A", "AnInterface", foo=function(x, ...) {
>    sum(slot(x, "x"))
> })
> getImplementation("A", "AnInterface")
>
> setGeneric("baz", function(intrfc, ...) standardGeneric("baz"))
> ## dispatch on the interface
> setMethod("baz", "AnInterface", function(intrfc, ...) {
>    ## use the implementation
>    impl <- getImplementation(intrfc, "AnInterface")
>    impl$foo(impl)
> })
>
> a <- new("A", x=1:5)
> baz(a)
>
> _______________________________________________
> Bioc-devel@stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>
>

	[[alternative HTML version deleted]]

