[Rd] NAMESPACEs and S4 classes

Martin Morgan mtmorgan at fhcrc.org
Tue Feb 19 07:41:49 CET 2008


Thank you for the explanation; I saw that class definitions were
stored in package-level .__C__* and in a global cache
methods:::.classTable, but was not sure which was meant to be
definitive.

I'm hoping your bug fix will address identically named sealed classes
in different packages -- I hope to use 'sealed' as a way to reduce
programming errors associated with unintentionally overwriting
existing class definitions (the classes are generated
programmatically, and a name conflict escaped my notice; I thought a
'better practice' would be to seal class definitions that I did not
intend to change).

The class hierarchies I am working with are large. I hope to avoid
regenerating them each time the package is loaded, e.g., using a lazy
load data base built when the package is installed. I can see how this
might work when class definitions are in package-level variables
.__C__*, but am less clear about how lazy loaded class definitions
might be added to a globally cached class table.

My more ambitious hope is to manage identically named classes from
separate hierarchies in the same package, e.g., by placing each
hierarchy in a separate environment (with attribute 'name' set, so
environmentName() returns something sensible). I realize this does not
work with the current implementation, but offer it as a potential use
case.

Thank you again for your help.

Martin

John Chambers <jmc at r-project.org> writes:

> Let's start from a simpler description,  because the use of "sealed" adds some
> confusion.  Here's a basic version.   I have two packages, P2 and P3, with
> different definitions of "myClass".
> Classes with the same name on two packages are supposed to work, at least for
> generating objects.  There is a bug (see below) and a workaround, but with or
> without the workaround you need to apply new() to a class _object_, not just a
> name, if you want to generate objects in the global environment.
> Here's what currently works, using the workaround:
>> c2 = get(classMetaName("myClass"), envir = asNamespace("P2"))
>> c3 = get(classMetaName("myClass"), envir = asNamespace("P3"))
>> x2 = new(c2)
>> x3 = new(c3)
>> class(x2)
> [1] "myClass"
> attr(,"package")
> [1] "P2"
>> class(x3)
> [1] "myClass"
> attr(,"package")
> [1] "P3"
> By using asNamespace(), it's not necessary to export the class definitions,
> and possibly better not to.
> Two comments:
> - The bug is that you should be able to use
>    c2 = getClass("myClass", asNamespace("P2"))
> instead of the call to get().  But a current misuse of cached definitions
> means that only the first definition is known.  Hence the need for a
> workaround using classMetaName() to get the class definition directly.  I
> think the fix is easy & will try to add it to r-devel fairly soon.
> - There are limitations to using duplicated class names, because not all
> computations will carry the appropriate package information to say which
> "myClass" we mean.  So if one can avoid duplicating class names, life will be
> easier, and I suspect that duplicated classes that are _not_ exported will
> work better, because computations will be forced into the individual
> namespaces with less chance for getting the wrong definition.
> Martin Morgan wrote:
>
>           I'd like to have two packages with S4 classes with the same name but
> different implementation. To that end I create a package tmpA with
>
> setClass("A",
>          representation=representation(
>            x="numeric"),
>          sealed=TRUE)
> setClass("B",
>          representation=representation(
>            x="numeric"))
> B <- function(...) new("B", ...)
>
> and a NAMESPACE having only
>
> import(methods)
> export(B)
>
> I duplicate this package source directory structure, renaming the
> duplicate package tmpB in its Description file. After R CMD
> INSTALL'ing both, I
>
>   
>
>                     library(tmpA)
> library(tmpB)
>     
>
>
>      Error in setClass("A", representation = representation(x = "numeric"),  : 
>   "A" has a sealed class definition and cannot be redefined
> Error : unable to load R code in package 'tmpB'
> Error: package/namespace load failed for 'tmpB'
>   
>
>                     setClass("A", prototype(y="numeric"))
>     
>
>
>      Error in setClass("A", c(y = "numeric")) : 
>   "A" has a sealed class definition and cannot be redefined
>
> It appears that, although 'where' in setClass influences the location
> of the class definition, there is a global class table that means only
> one class of a particular name can ever be defined. Is that the
> intended behavior? 
>
> If I create a class B in the global environment
>
>   
>
>                     setClass("B", representation(y="numeric"))
>     
>
>
>      [1] "B"
>
> and then use the constructor from tmpA, I end up with an instance of
> the globally defined class B, rather than the one defined in the
> constructor's name space:
>
>   
>
>                     B()
>     
>
>
>      An object of class "B"
> Slot "y":
> numeric(0)
>
> How would I write B to return an instance of B as defined in tmpA?
>
> Thanks,
>
> Martin
>
>   
>
>                     sessionInfo()
>     
>
>
>      R version 2.7.0 Under development (unstable) (2008-02-09 r44397) 
> x86_64-unknown-linux-gnu 
>
> locale:
> LC_CTYPE=en_US.UTF-8;LC_NUMERIC=C;LC_TIME=en_US.UTF-8;LC_COLLATE=en_US.UTF-8;LC_MONETARY=en_US.UTF-8;LC_MESSAGES=en_US.UTF-8;LC_PAPER=en_US.UTF-8;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=en_US.UTF-8;LC_IDENTIFICATION=C
>
> attached base packages:
> [1] stats     graphics  grDevices datasets  utils     methods   base     
>
> other attached packages:
> [1] tmpA_1.0
>
>   
>

-- 
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



More information about the R-devel mailing list