From jmc at r-project.org  Fri Jun 24 22:04:01 2011
From: jmc at r-project.org (John Chambers)
Date: Fri, 24 Jun 2011 13:04:01 -0700
Subject: [Rd] Class not found when search in .onLoad
In-Reply-To: <4E044276.1070002@cbio.uct.ac.za>
References: <4E0321DE.2020601@cbio.uct.ac.za> <4E036D6E.3000509@r-project.org>
	<4E044276.1070002@cbio.uct.ac.za>
Message-ID: <4E04EDB1.70105@r-project.org>

On 6/24/11 12:53 AM, Renaud Gaujoux wrote:
> Thank you John for your response.
>
> Things are a little bit more complicated though. The inheritance checks
> are not only made in .onLoad, they are part of a class validity method,
> which is called in .onLoad because some objects from this class are
> created at this stage. Such objects can also be created at any moment,
> not in a call from .onLoad.
>
> More or less briefly:
> class 'A' is in fact a virtual class defined in the package's namespace,
> with the purpose of defining a common interface. While the package does
> provide some derived classes (i.e. defined within the namespace), users
> too must be able to define derived classes from 'A' (i.e. not defined
> within the namespace).
> In another class from the namespace, the validity method checks that one
> of its character slot contains the name of a class that inherits from
> interface 'A'.

Strictly speaking, that is not meaningful.  A class (like any R object) 
is uniquely referenced by a name *and an environment*.  The name of a 
package can be used to construct the environment, but your "character 
slot" won't identify a class reliably unless the character string has a 
"package" attribute.

Look at class(x), for example, from an object from one of these classes. 
  It will have a "package" attribute identifying the package.
The character string with the package attribute is what you should be 
storing in the slot (or else store the class definition---takes more 
space but is slightly more efficient).

>
> I was just expecting `isClass` and `extends` to also work in .onLoad
> without specifying the argument `where` (i.e. searching everywhere,
> starting by the package's namespace if called within a namespace). The
> argument `where` being there to allow finer search.
>
> There is no argument pkgname to the validity method, to directly apply
> the work around. I guess I can always check the presence of the class in
> the some-how hard-coded namespace, and if it is not found there look for
> the class elsewhere:
>
> #...
> clref <- getClass('A', .Force=TRUE, where=THE.NAMESPACE)
> cl <- getClass(name, .Force=TRUE, where=THE.NAMESPACE)
> if( is.null(cl) )
> cl <- getClass(name, .Force=TRUE)
>
> if( !extends(cl, clref) )
> return('invalid slot')
> #...
>
> I will use this, in last resort, although it feels strange as it will
> only be to deal with the case where objects are created within a call to
> .onLoad.
>
> I am really interested in understanding why all this:
>
> - what makes this call so different?
> In my sample package, if I add a call `check.classes()` directly in
> script.R, the classes are correctly found when the installation sources
> the script prepare the package for lazy loading.
> - why things seemed to work ok in R-2.12.1 at the installation loading
> check, but do not work when loading the package from an R session?
>
> Could you please briefly give some explanations or pointers?
>
> Thank you.
>
> Bests,
> Renaud
>
> On 23/06/2011 18:44, John Chambers wrote:
>> The workaround is to use the package's namespace, as you did. That's
>> one of the reasons why pkgname is an argument to .onLoad().
>>
>> Depending on what you want to do, you can either use the namespace as
>> an argument where= or get the class definition from the namespace and
>> use it in place of the class name.
>>
>> A side advantage is that such checks work regardless of whether or not
>> the classes, etc. are exported from the package. Also, on the remote
>> chance there is another class of the same name, the check works
>> unambiguously on your package's version.
>>
>> The relevant part of your script, modified accordingly, seems to work
>> as desired.
>>
>> John
>>
>> ############
>> # script.R
>> ############
>>
>> setClass('A', representation(data='numeric'))
>>
>> setClass('B', contains='A') # the argument is contains=
>>
>> check.classes <- function(where){
>>
>> message("isClass('A', where = where): ", methods::isClass('A', where =
>> where))
>>
>> message("isClass('B', where = where): ", methods::isClass('B', where =
>> where))
>>
>> classA <- getClass('A', where = where)
>> classB <- getClass('B', where = where)
>> message("extends(classB, classA): ", methods::extends(classB, classA))
>> }
>>
>> .onLoad <- function(libname, pkgname=NULL){
>> cat("\n## .onLoad ##\n")
>> check.classes(asNamespace(pkgname))
>> }
>>
>> .onAttach <- function(libname, pkgname){
>> cat("\n## .onAttach ##\n")
>> check.classes(asNamespace(pkgname))
>> }
>>
>>
>>
>>
>> On 6/23/11 4:22 AM, Renaud Gaujoux wrote:
>>> Hi,
>>>
>>> I am facing with a strange behaviour of isClass and extends when these
>>> are called in .onLoad in both R 2.12.1 and R 2.13.0. This is preventing
>>> my package from doing some object initializations at a proper place
>>> (i.e. in .onLoad).
>>>
>>> Suppose one defines two S4 classes in a package, and that one needs to
>>> check the inheritance between these two when loading the package (e.g.
>>> to validate slots in objects).
>>> See package attached or code below (not sure attachments can go
>>> through).
>>>
>>> in R 2.13.0:
>>> At the loading check after installation, the classes are not found by
>>> `isClass` and `extends` when these are called in .onLoad, but are
>>> correctly found when called in .onAttach.
>>> However findClass correctly finds the class in both case, as well as
>>> isClass if it is called with the argument
>>> `where=asNamespace('<THE.PACKAGE.NAME>')`.
>>> When the package is loaded from an open R session, the behaviour is the
>>> same.
>>>
>>> in R 2.12.1:
>>> the classes are correctly found by isClass and extends when these are
>>> called in .onLoad or .onAttach, but only at installation (i.e. at the
>>> loading check after R CMD INSTALL).
>>> When the package is loaded from an open R session, one fails to find the
>>> classes only in .onLoad while in .onAttach they are correctly found.
>>>
>>> This is really an issue as up to now I was using .onAttach to do my
>>> checks and initialization, but it is not a wise thing as package that
>>> would only need to import my package (load and not attach) will not get
>>> internal objects properly initialized. All this should be done in
>>> .onLoad, but I cannot do it due to this behaviour of `extends`.
>>>
>>> Can someone provide some explanations or work around.
>>>
>>> Thank you,
>>> Renaud
>>>
>>>
>>> ############
>>> # script.R
>>> ############
>>>
>>> setClass('A', representation(data='numeric'))
>>>
>>> setClass('B', contain='A')
>>>
>>> check.classes <- function(){
>>>
>>> a <- new('A')
>>> b <- new('B')
>>>
>>> message("isClass('A'): ", methods::isClass('A'))
>>> message("isClass('A') in namespace: ", methods::isClass('A',
>>> where=asNamespace('anRpackage')))
>>> message("findClass('A'): ")
>>> print(methods::findClass('A'))
>>>
>>> message("isClass('B'): ", methods::isClass('B'))
>>> message("isClass('B') in namespace: ", methods::isClass('B',
>>> where=asNamespace('anRpackage')))
>>> message("findClass('B'): ")
>>> print(methods::findClass('B'))
>>>
>>> message("extends('B', 'A'): ", methods::extends('B', 'A'))
>>> message("is(a, 'A'): ", is(a, 'A'))
>>> message("inherits(a, 'A'): ", inherits(a, 'A'))
>>> message("is(b, 'A'): ", is(b, 'A'))
>>> }
>>>
>>> .onLoad <- function(libname, pkgname=NULL){
>>> cat("\n## .onLoad ##\n")
>>> check.classes()
>>> }
>>>
>>> .onAttach <- function(libname, pkgname){
>>> cat("\n## .onAttach ##\n")
>>> check.classes()
>>> }
>>> ############
>>>
>>>
>> ..............
>>>
>>> ###
>>> UNIVERSITY OF CAPE TOWN
>>> This e-mail is subject to the UCT ICT policies and e-mail disclaimer
>>> published on our website at
>>> http://www.uct.ac.za/about/policies/emaildisclaimer/ or obtainable from
>>> +27 21 650 9111. This e-mail is intended only for the person(s) to whom
>>> it is addressed. If the e-mail has reached you in error, please notify
>>> the author. If you are not the intended recipient of the e-mail you may
>>> not use, disclose, copy, redirect or print the content. If this e-mail
>>> is not related to the business of UCT it is sent by the sender in the
>>> sender's individual capacity.
>>>
>>> ###
>>>
>>>
>>>
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
>
> ###
> UNIVERSITY OF CAPE TOWN
> This e-mail is subject to the UCT ICT policies and e-mai...{{dropped:5}}
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



[Rd] Class not found when search in .onLoad
John Chambers