[Rd] S3 dispatch does not work for generics defined inside an environment

Taras Zakharko t@r@@@z@kh@rko @end|ng |rom uzh@ch
Wed Jun 30 12:51:45 CEST 2021


@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 <josh.m.ulrich using gmail.com> wrote:
> 
> On Wed, Jun 30, 2021 at 5:17 AM Duncan Murdoch <murdoch.duncan using gmail.com> 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
>> 
>> ______________________________________________
>> R-devel using r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
> 
> 
> 
> -- 
> Joshua Ulrich  |  about.me/joshuaulrich
> FOSS Trading  |  www.fosstrading.com



More information about the R-devel mailing list