[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