Reputation: 155
I have a preprocessing package with a wrapper function that helps the user to use inheritance. These user-defined classes and methods can not be stored to the sealed package namespace as I have done with top-level code default classes and methods. What is the correct environment to assign the definitions into? The solution below seems to work somehow but I don't understand it well enough.
setpreprocessor <- function(classname, operation, mode="numeric"){
setClass(classname, contains="PreprocessorClass",
where=topenv(parent.frame()), prototype=prototype(objectname=classname,
objectoperation=operation))
setMethod("transformdata", where=topenv(parent.frame()), signature(object =
classname), function(object, dataobject) {
...code here uses arguments "operation" and "mode"...
})
}
Upvotes: 2
Views: 266
Reputation: 46866
Here's a more complete example, with some formatting to make the structure of the code a little more apparent
setClass("PreprocessorClass")
setGeneric("transformdata",
function(object, dataobject) standardGeneric("transformdata"))
setpreprocessor <- function(classname, operation, mode="numeric") {
setClass(classname, contains="PreprocessorClass",
where=topenv(parent.frame()),
prototype=prototype(objectname=classname,
objectoperation=operation))
setMethod("transformdata", signature(object = classname),
where=topenv(parent.frame()),
function(object, dataobject) {
## code that uses 'operation', 'mode'
list(operation, mode)
})
}
parent.frame()
is the environment from which the function is called (not the environment in which the function is defined).
Almost all environments have an enclosing environment, typically the environment in which the environment itself was defined; see ?parent.env
. topenv()
starts from the specified argument, and traces enclosing environments of each environment until it reaches .GlobalEnv or a package namespace.
So if your code were in a package PkgA, the user loaded the package, and then invoked setpreprocessor("Foo", "bar")
from the global environment (command prompt), parent.frame()
would return .GlobalEnv
, as would topenv()
. You would see
> ls(all=TTRUE)
[1] ".__C__Foo" ".__T__transformdata:PkgA"
which are the class and method definitions created in the global environment.
On the other hand, if the user used setpreprocessor()
in a function in a package, topenv(parent.frame())
would end up at the (sealed) package namespace. Because the package namespace is sealed, it would not be possible to create the class or method definitions.
An alternative is to provide an environment into which the class and method definitions can be cached
.PreprocessorCache <- new.env()
setClass("PreprocessorClass")
## ...
and then use
where=.PreprocessorCache
in the class and method definitions. setpreprocessor()
can then be invoked either interactively or in package code.
Upvotes: 3