I had another glance at the code and now I’m convinced that this is the bug in
registerS3method(). Default R behavior (in objects.c) appears to be to look for
method definitions in the top environment, not the defining environment, but
registerS3method() registers the method in the defining environment. I think
registerS3method() should be changed to something like:
- if (typeof(genfun) == "closure”)
- environment(genfun)
------------
+ if (typeof(genfun) == "closure”)
+ if(isFALSE(Sys.getenv("_R_S3_METHOD_LOOKUP_USE_TOPENV_AS_DEFENV_”))
environment(genfun) else topenv(environment(genfun))
in order to match the behavior of do_usemethod()
Best,
Taras
> On 30 Jun 2021, at 12:51, Taras Zakharko <[email protected]> wrote:
>
> @Duncan: .S3method() calls registerS3method() with appropriate environmental
> argument under the good, so that’s not the problem.
>
> Anyway, I’ve been doing some debugging and I think I have found the issue.
> The following snippet in src/objects.c
> (https://github.com/wch/r-source/blob/ecc633b37d77fdd1cb27dda74d7f6b3684f0c01c/src/main/objects.c#L525)
> sets the global lookup_use_topenv_as_defenv variable:
>
>
> if(lookup_use_topenv_as_defenv == -1) {
> lookup = getenv("_R_S3_METHOD_LOOKUP_USE_TOPENV_AS_DEFENV_");
> lookup_use_topenv_as_defenv =
> ((lookup != NULL) && StringFalse(lookup)) ? 0 : 1;
> }
>
> Isn’t that supposed to be
>
> lookup_use_topenv_as_defenv = ((lookup != NULL) &&
> StringFalse(lookup)) ? 1 : 0;
>
> instead?
>
> The way the code works right now, methods will be looked up in top
> environment exactly if _R_S3_METHOD_LOOKUP_USE_TOPENV_AS_DEFENV_ is not set.
> This seems incompatible with what registerS3method() does (setting the
> .__S3MethodsTable__. on the defining environment instead of the topenv). When
> I change 0 and 1 around, everything works as expected.
>
> In the meantime, I can work around it by manually injecting
> __S3MethodsTable__ into .GlobalEnv (which is my topenv here).
>
> I can open a bug report, but I would like to wait for some more comments.
>
> Best,
>
> Taras
>
>> On 30 Jun 2021, at 12:39, Joshua Ulrich <[email protected]> wrote:
>>
>> On Wed, Jun 30, 2021 at 5:17 AM Duncan Murdoch <[email protected]>
>> wrote:
>>>
>>> On 30/06/2021 5:22 a.m., Taras Zakharko wrote:
>>>> Dear all,
>>>>
>>>> I have a generic function and a bunch of methods defined in a separate
>>>> environment. Here is a reduced example:
>>>>
>>>> env <- local({
>>>> # define the generic function and the method
>>>> myfun <- function(x) UseMethod("myfun")
>>>> myfun.myclass <- function(x) print("called myfun.myclass”)
>>>>
>>>> # register the method
>>>> .S3method("myfun", "myclass", myfun.myclass)
>>>>
>>>> environment()
>>>> })
>>>>
>>>> Since the method has been registered, I hoped that invocation like this
>>>> would work:
>>>>
>>>> env$myfun(structure(0, class = "myclass”))
>>>>
>>>> However, this results in a “no applicable method" error.
>>>>
>>>> It is my understanding that registerS3method (called by .S3method) will
>>>> install the method string in the .__S3MethodsTable__. table of the
>>>> environment where the generic function is defined, and this table is
>>>> subsequently used by usemethod() inside R, so I am puzzled that the
>>>> dispatch does not work. I checked and the .__S3MethodsTable__. of env is
>>>> indeed setup correctly. I also tried manually adding the method string to
>>>> the global .__S3MethodsTable__. inside .BaseNamespaceEnv to no effect.
>>>>
>>>> In fact, the only way to make it work is to define either myfun or
>>>> myfun.myclas in the global environment, which is something I would like to
>>>> avoid.
>>>>
>>>> Thank you in advance for any pointers!
>>>>
>>>
>>> registerS3method has an additional parameter "envir" which I believe
>>> would end up set to env in your code. So this works:
>>>
>>>> eval(expression(myfun(structure(0, class = "myclass"))), envir = env)
>>> [1] "called myfun.myclass"
>>>
>>> You could probably also call registerS3method with envir specified
>>> appropriately and get your original expression to work.
>>>
>> That doesn't seem to work on 4.1.0 for me. The code below worked for
>> me in Oct-2020, though I'm not sure what version of R I was using at
>> the time. I was slow to upgrade to 4.0, so it was probably the latest
>> 3.x version.
>>
>> env <- new.env()
>> local({
>> # define the generic function and the method
>> myfun <- function(x) { UseMethod("myfun", x) }
>>
>> # register the method
>> registerS3method("myfun", "myclass",
>> function(x) { print("called myfun.myclass") },
>> envir = env)
>> }, envir = env)
>> attach(env)
>> myfun(structure(0, class = "myclass"))
>>
>>
>>> Duncan Murdoch
>>>
>>> ______________________________________________
>>> [email protected] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>>
>> --
>> Joshua Ulrich | about.me/joshuaulrich
>> FOSS Trading | www.fosstrading.com
>
______________________________________________
[email protected] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel