From mtmorgan at fhcrc.org  Fri Apr 20 21:02:53 2007
From: mtmorgan at fhcrc.org (Martin Morgan)
Date: Fri, 20 Apr 2007 12:02:53 -0700
Subject: [Rd] setClass inside a function
In-Reply-To: <40A15E1D8A76A949AF0271EF3133E1A9CF7E6B@LOWEXPRESS.corp.cefas.co.uk>
	(Iago Mosqueira's message of "Fri, 20 Apr 2007 17:31:51 +0100")
References: <40A15E1D8A76A949AF0271EF3133E1A9CF7E6B@LOWEXPRESS.corp.cefas.co.uk>
Message-ID: <6ph1wie98de.fsf@gopher4.fhcrc.org>

"Iago Mosqueira (Cefas)" <Iago.Mosqueira at cefas.co.uk> writes:

> Hi Martin,
>
> Thanks very much for your help.
>
>> Hi Iago --
>> 
>> Here's my attempt at an answer.
>> 
>> "Iago Mosqueira (Cefas)" <Iago.Mosqueira at cefas.co.uk> writes:
>> 
>> > set of S4 classes. But setClass is choking when my function 
>> is called
>> > isnide a package, telling about an error in exists(cname, where). I
>> > assume this to be a problem with the environment where the class is
>> > created. If I define my creator function in a package and load it,
>> > when I call it I get
>> >
>> > Error in assign(mname, def, where): cannot add bindings to a locked
>> > environment
>> 
>> You're trying to create a class in the package name space, and the
>> name space is locked (cannot be modified) after the package is
>> loaded. If your intention is programmatically generate static classes
>> (in a kind of macro-like way) then I think you could still use this
>> approach but ensure that the classes are created when the package is
>> loaded (e.g., by including a class creation function that is actually
>> evaluated, not just defined, in your package code). 
>
> Yes, I have tried that. Inmediatly after the creator function is
> defined I use it to create a new class. And this class is exported
> in the package NAMESPACE. Still, it says the package environment is
> locked, although the call to setClass is part of the package.

Try removing the 'where' argument in setClass; or replacing it with
topenv(parent.frame()) -- the top environment when the package is
loaded is the name space.

Also, for fun,

>> > 	# validity
>> > 	foo <- "validity <- function(object) {"
>> > 	# foo <- c(foo, "browser()")
>> > 	foo <- c(foo, paste("if(all(names(dimnames(object)) != c('",
>> > 		paste(names(dimnames), collapse="','", sep=""), "')))",
>> > sep=""))
>> > 	foo <- c(foo, "stop(paste('dimnames are not correct for class',
>> > name))")
>> > 	foo <- c(foo, "return(TRUE)}")
>> > 	eval(parse(text=foo))

you can write something like

    validity <- function (object) {
        msg <- NULL
        cat("checking", name, "/", class(object), "validity\n")
        if (all(names(dimnames(object)) != c("iter", "y"))) 
            msg <- paste("dimnames are not correct for class", name)
        if (is.null(msg)) TRUE
        else msg
    }

and continue to include validity=validity in setClass. This will use
R's lexical scope to figure out the correct name, etc for each class
created. Note also that the idea is that the validity function either
returns TRUE or a character string, not itself calling 'stop'.

>> > 	# constructors
>> > 	eval(parse(text=paste("setGeneric('", name,
>> > 		"', function(object, ...) standardGeneric('", 
>> name, "'))",
>> > sep="")))

I had expected that

    setGeneric(name,
               function(object, ...) standardGeneric(name))

would work, but apparently not. This might be a bit cleaner way to
create complcated substitutions;

    eval(substitute({
        setGeneric(NAME,
                   function(object, ...) {
                       standardGeneric(NAME)
                   })
        }, list(NAME=name)))

>> > 	setMethod(name, signature(object='missing'),
>> > 		function(...) {
>> > 			return(FLPar(..., class=name))
>> > 		}
>> > 	)

It's a bit surprising that this setMethod works, as the function
signature is different from the generic. This might cause problems
further down the line. I would have thought that the correct
formulation would be along the lines of

    setMethod(name, signature(object='missing'),
              function(object, ...) {
                  FLPar(..., class=name)
              })

Martin
-- 
Martin Morgan
Bioconductor / Computational Biology
http://bioconductor.org



[Rd] setClass inside a function
Martin Morgan