[R-pkg-devel] Unfortunate function name generic.something

Michael Dewey ||@t@ @end|ng |rom dewey@myzen@co@uk
Tue May 9 14:31:07 CEST 2023


Dear Ulrike

Even though it will undobtedly be a lot of work to rename levels.no I 
cannot help feeling that by fighting against the system you may be 
storing up trouble for yourself in future when some upgrade breaks your 
current solution and you have to make yet more changes.

Michael

On 09/05/2023 07:13, Ulrike Groemping wrote:
> Am 09.05.2023 um 01:23 schrieb Duncan Murdoch:
>> On 08/05/2023 6:58 p.m., Simon Urbanek wrote:
>>>
>>>
>>>> On 8/05/2023, at 11:58 PM, Duncan Murdoch <murdoch.duncan using gmail.com> 
>>>> wrote:
>>>>
>>>> There really isn't such a thing as "a function that looks like an S3 
>>>> method, but isn't".  If it looks like an S3 method, then in the 
>>>> proper circumstances, it will be called as one.
>>>>
>>>
>>>
>>> I disagree - that was the case in old versions, but not anymore. The 
>>> whole point of introducing namespaces and method registration was to 
>>> make it clear when a function is a method and when it is a function. 
>>> If you export a function it won't be treated as a method:
>>>
>>> In a package NAMESPACE:
>>> export(foo.cls)
>>> package R code: foo.cls <- function(x) "foo.cls"
>>>
>>> in R:
>>>> cls=structure(1,class="cls")
>>>> foo=function(x) UseMethod("foo")
>>>> foo(cls)
>>> Error in UseMethod("foo") :
>>>    no applicable method for 'foo' applied to an object of class "cls"
>>>> foo.cls(cls)
>>> [1] "foo.cls"
>>>
>>> So R knows very well what is a method and what is a function. If you 
>>> wanted it to be a method, you have to use S3method(foo, cls) and that 
>>> **is** different from export(foo.cls) - quite deliberately so.
>>
>> That is true for package users, but it's not true within the package. 
>> I just tested this code in a package:
>>
>>   levels.no <- function(xx, ...) {
>>     stop("not a method")
>>   }
>>
>>   f <- function() {
>>     x <- structure(1, class = "no")
>>     levels(x)
>>   }
>>
>> Both levels.no and f were exported.  If I attach the package and call 
>> f(), I get the error
>>
>>   > library(testpkg)
>>   > f()
>>   Error in levels.no(x) : not a method
>>
>> because levels.no is being treated as a method when levels() is called 
>> in the package.
>>
>> If I create an x like that outside of the package and call levels(x) 
>> there, I get NULL, because levels.no is not being treated as a method 
>> in that context.
>>
>> As far as I know, there is no possible way to have a function in a 
>> package that is called "levels.no" and not being treated as a method 
>> within the package.  I don't think there's any way to declare "this is 
>> not a method", other than naming it differently.
>>
>> Duncan
> 
> Before the current check notes, I did not think about that problem. I 
> think that it is quite unlikely to hit a user of mine, because the 
> package calls levels() in a few places on columns of designs only. I 
> still think that it should remain possible to have an *internal* 
> function that is named in whatever way I like it named (I would of 
> course not choose that name now, but it's there, and it would break a 
> lot of my own non-package code if I changed it in the package). My 
> current "fix" made the problem worse.
> Would it have been permissible to not register the function ? I could 
> then revert to not registering it, but keeping the error message in 
> place, just in case the unlikely event happens.
> 
> Ulrike
> 
>>
>>>
>>> Cheers,
>>> Simon
>>>
>>>
>>>> In your case the function name is levels.no, and it isn't exported. 
>>>> So if you happen to have an object with a class inheriting from 
>>>> "no", and you call levels() on it, levels.no might be called.
>>>>
>>>> This will only affect users of your package indirectly.  If they 
>>>> have objects inheriting from "no" and call levels() on them, 
>>>> levels.no will not be called.  But if they pass such an object to 
>>>> one of your package functions, and that function calls levels() on 
>>>> it, they could end up calling levels.no(). It all depends on what 
>>>> other classes that object inherits from.
>>>>
>>>> You can test this yourself.  Set debugging on any one of your 
>>>> functions, then call it in the normal way.  Then while still in the 
>>>> debugger set debugging on levels.no, and create an object using
>>>>
>>>>   x <- structure(1, class = "no")
>>>>
>>>> and call levels(x).  You should break to the code of levels.no.
>>>>
>>>> That is why the WRE manual says "First, a caveat: a function named 
>>>> gen.cl will be invoked by the generic gen for class cl, so do not 
>>>> name functions in this style unless they are intended to be methods."
>>>>
>>>> So probably the best solution (even if inconvenient) is to rename 
>>>> levels.no to something that doesn't look like an S3 method.
>>>>
>>>> Duncan Murdoch
>>>>
>>>> On 08/05/2023 5:50 a.m., Ulrike Groemping wrote:
>>>>> Thank your for the solution attempt. However, using the keyword 
>>>>> internal
>>>>> does not solve the problem, the note is still there. Any other 
>>>>> proposals
>>>>> for properly documenting a function that looks like an S3 method, 
>>>>> but isn't?
>>>>> Best, Ulrike
>>>>> Am 05.05.2023 um 12:56 schrieb Iris Simmons:
>>>>>> You can add
>>>>>>
>>>>>> \keyword{internal}
>>>>>>
>>>>>> to the Rd file. Your documentation won't show up the in the pdf
>>>>>> manual, it won't show up in the package index, but you'll still be
>>>>>> able to access the doc page with ?levels.no <http://levels.no> or
>>>>>> help("levels.no <http://levels.no>").
>>>>>>
>>>>>> This is usually used in a package's deprecated and defunct doc pages,
>>>>>> but you can use it anywhere.
>>>>>>
>>>>>> On Fri, May 5, 2023, 06:49 Ulrike Groemping
>>>>>> <ulrike.groemping using bht-berlin.de> wrote:
>>>>>>
>>>>>>      Dear package developeRs,
>>>>>>
>>>>>>      I am working on fixing some notes regarding package DoE.base.
>>>>>>      One note refers to the function levels.no <http://levels.no> and
>>>>>>      complains that the
>>>>>>      function is not documented as a method for the generic function
>>>>>>      levels.
>>>>>>      Actually, it is not a method for the generic levels, but a 
>>>>>> standalone
>>>>>>      internal function that I like to have documented.
>>>>>>
>>>>>>      Is there a way to document the function without renaming it and
>>>>>>      without
>>>>>>      triggering a note about method documentation?
>>>>>>
>>>>>>      Best, Ulrike
>>>>>>
>>>>>>      --
>>>>>>      ##############################################
>>>>>>      ## Prof. Ulrike Groemping
>>>>>>      ## FB II
>>>>>>      ## Berliner Hochschule für Technik (BHT)
>>>>>>      ##############################################
>>>>>>      ## prof.bht-berlin.de/groemping 
>>>>>> <http://prof.bht-berlin.de/groemping>
>>>>>>      ## Phone: +49(0)30 4504 5127
>>>>>>      ## Fax:   +49(0)30 4504 66 5127
>>>>>>      ## Home office: +49(0)30 394 04 863
>>>>>>      ##############################################
>>>>>>
>>>>>>      ______________________________________________
>>>>>>      R-package-devel using r-project.org mailing list
>>>>>>      https://stat.ethz.ch/mailman/listinfo/r-package-devel
>>>>>>
>>>>> ______________________________________________
>>>>> R-package-devel using r-project.org mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>>>>
>>>> ______________________________________________
>>>> R-package-devel using r-project.org mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>>>>
>>>
>>
> 
> ______________________________________________
> R-package-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-package-devel
> 

-- 
Michael
http://www.dewey.myzen.co.uk/home.html



More information about the R-package-devel mailing list