Taras Zakharko
2021-Jun-30 09:22 UTC
[Rd] S3 dispatch does not work for generics defined inside an environment
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!
Best,
Taras
P.S. If you are wondering what I am trying to achieve here ? we have a very
large codebase and I am trying to use environments as a type of ?poor man?s
namespaces? to organize code in a modular fashion. But of course it?s all
pointless if I can?t get the generics to work reliably.
Duncan Murdoch
2021-Jun-30 10:17 UTC
[Rd] S3 dispatch does not work for generics defined inside an environment
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. Duncan Murdoch
Greg Minshall
2021-Jul-01 03:55 UTC
[Rd] S3 dispatch does not work for generics defined inside an environment
Taras,> P.S. If you are wondering what I am trying to achieve here ? we have a > very large codebase and I am trying to use environments as a type of > ?poor man?s namespaces? to organize code in a modular fashion. But of > course it?s all pointless if I can?t get the generics to work > reliably.i'm not knowledgeable about S3. but, a different way to try to modularize large code bases is to split them into separate packages. just in case you hadn't already thought about, and rejected, that idea. cheers, Greg