[R-pkg-devel] unregistered S3 methods in a package
Martin Maechler
m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Thu Sep 5 09:44:52 CEST 2024
>>>>> Uwe Ligges
>>>>> on Thu, 5 Sep 2024 08:47:06 +0200 writes:
> Dear John,
> the question is not really easy to answer, but there is a nice summary
> Kurt pointed me to: The code of checkS3methods() includes the following
> comments with the last paragraph containing the short answer to your
> question:
> ## Check S3 generics and methods consistency.
> ## Unfortunately, what is an S3 method is not clear.
> ## These days, S3 methods for a generic GEN are found
> ## A. via GEN.CLS lookup from the callenv to its topenv;
> ## B. the S3 registry;
> ## C. GEN.CLS lookup from the parent of the topenv to baseenv,
> ## skipping everything on the search path between globalenv and
> ## baseenv.
> ## Thus if "package code" calls GEN, we first look in the package
> ## namespace itself, then in the registry, and then in the package
> ## imports and .BaseNamespaceEnv (and globalenv and baseenv again).
> ##
> ## Clearly, everything registered via S3method() should be an S3
> ## method. Interestingly, we seem to have some registrations for
> ## non-generics, such as grDevices::axis(). These are "harmless"
> ## but likely not "as intended", and hence inconsistencies are not
> ## ignored.
> ##
> ## If the package namespace has a function named GEN.CLS, it is used
> ## as an S3 method for an S3 generic named GEN (and hence "is an S3
> ## method") only if the package code actually calls GEN (see A
> ## above). So one could argue that we should not be looking at all
> ## GEN.CLS matches with GEN a generic in the package itself, its
> ## imports or base, but restrict to only the ones where the package
> ## code calls GEN. Doable, but not straightforward (calls could be
> ## PKG::GEN) and possibly quite time consuming. For generics from
> ## the package itself or its imports, not restricting should not
> ## make a difference (why define or import when not calling?), but
> ## for generics from base it may: hence we filter out the mismatches
> ## for base GEN not called in the package.
> ##
> ## If a package provides an S3 generic GEN, there is no need to
> ## register GEN.CLS functions for "internal use" (see above).
> ## However, if GEN is exported then likely all GEN.CLS functions
> ## should be registered as S3 methods.
> Best wishes,
> Uwe
Excellent! Thank you, Uwe, for digging this out.
I'd also had answered to John Fox (even more strongly)
that it *must* remain to be allowed to define "private"
S3 methods in a package in all cases:
- for a generic from the package (where the generic would also
not be exported)
- for a generic from another package (which is imported)
or base (which need not and cannot be imported).
Note that the same is possible with S4 and (AFAIK, untested)
with S7. {which people should really try using more ... }
Martin
> On 05.09.2024 00:10, John Fox wrote:
>> Thanks Toby and Jeff for chiming in on this.
>>
>> Jeff: I already read Kurt Hornik's post on "S3 Method Lookup" and quite
>> a few other sources.
>>
>> The main point is that failing to register the methods works in that the
>> methods are nevertheless invoked internally by functions in the package
>> but don't shadow versions of the methods registered by other package
>> externally (e.g., at the command prompt), which was the effect that I
>> wanted. Moreover, as I said, R CMD check (unlike roxygen) didn't complain.
>>
>> As I mentioned, this is now moot for the cv package, but I'm still
>> interested in the answer, as, apparently, is Toby.
>>
>> Best,
>> John
>>
>> On 2024-09-04 5:12 p.m., Jeff Newmiller wrote:
>>> Caution: External email.
>>>
>>>
>>> I have been reluctant to pipe up on this because I am no expert on the
>>> dark corners of the S3 dispatch mechanism, but I think unregistered S3
>>> methods in packages are verboten. Perhaps [1] will shed some light?
>>>
>>> [1] https://blog.r-project.org/2019/08/19/s3-method-lookup/
>>>
>>> On September 4, 2024 11:21:22 AM PDT, Toby Hocking <tdhock5 using gmail.com>
>>> wrote:
>>>> I got this warning too, so I filed an issue to ask
>>>> https://github.com/r-lib/roxygen2/issues/1654
>>>>
>>>> On Mon, Sep 2, 2024 at 2:58 PM John Fox <jfox using mcmaster.ca> wrote:
>>>>>
>>>>> As it turned out, I was able to avoid redefining coef.merMod(),
>>>>> etc., by
>>>>> making a simple modification to the cv package.
>>>>>
>>>>> I'm still curious about whether it's OK to have unregistered S3 methods
>>>>> for internal use in a package even though that's no longer necessary
>>>>> for
>>>>> the cv package.
>>>>>
>>>>> On 2024-09-02 11:34 a.m., John Fox wrote:
>>>>> Caution: External email.
>>>>>>
>>>>>>
>>>>> Dear R-package-devel list members,
>>>>>>
>>>>> I want to introduce several unregistered S3 methods into the cv
>>>>> package
>>>>> (code at <https://github.com/gmonette/cv>). These methods have the
>>>>> form
>>>>>>
>>>>> coef.merMod <- function(object, ...) lme4::fixef(object)
>>>>>>
>>>>> The object is to mask, e.g., lme4:::coef.merMod(), which returns BLUPs
>>>>> rather than fixed effects, internally in the cv package but *not* to
>>>>> mask the lme4 version of the method for users of the cv package --
>>>>> that
>>>>> could wreak havoc with their work. Doing this substantially simplifies
>>>>> some of the code in the cv package.
>>>>>>
>>>>> My question: Is it legitimate to define a method in a package for
>>>>> internal use without registering it?
>>>>>>
>>>>> This approach appears to work fine, and R CMD check doesn't complain,
>>>>> although Roxygen does complain that the method isn't "exported"
>>>>> (actually, isn't registered).
>>>>>>
>>>>> Any advice or relevant information would be appreciated.
>>>>>>
>>>>> Thank you,
>>>>> John
>>>>> --
>>>>> John Fox, Professor Emeritus
>>>>> McMaster University
>>>>> Hamilton, Ontario, Canada
>>>>> web: https://www.john-fox.ca/
More information about the R-package-devel
mailing list