Viechtbauer, Wolfgang (SP)
2020-May-12 18:05 UTC
[Rd] S3 method dispatch for methods in local environments
Dear All, In R 3.6.3 (and earlier), method dispatch used to work for methods stored in local environments that are attached to the search path. For example: myfun <- function(y) { out <- list(y=y) class(out) <- "myclass" return(out) } print.myclass <- function(x, ...) print(formatC(x$y, format="f", digits=5)) myfun(1:4) # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" rm(print.myclass) myenv <- new.env() myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), myenv) attach(myenv) myfun(1:4) # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" But since R 4.0.0, this no longer words and the above prints: $y [1] 1 2 3 4 attr(,"class") [1] "myclass" Is this intended? And is there a way to still make this work? Best, Wolfgang
Martin Maechler
2020-May-12 19:05 UTC
[Rd] S3 method dispatch for methods in local environments
>>>>> Viechtbauer, Wolfgang (SP) >>>>> on Tue, 12 May 2020 18:05:32 +0000 writes:> Dear All, > In R 3.6.3 (and earlier), method dispatch used to work for methods stored in local environments that are attached to the search path. For example: > myfun <- function(y) { > out <- list(y=y) > class(out) <- "myclass" > return(out) > } > print.myclass <- function(x, ...) print(formatC(x$y, format="f", digits=5)) > myfun(1:4) > # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" > rm(print.myclass) > myenv <- new.env() > myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), myenv) > attach(myenv) > myfun(1:4) > # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" > But since R 4.0.0, this no longer words and the above prints: > $y > [1] 1 2 3 4 > attr(,"class") > [1] "myclass" > Is this intended? yes, most probably, unless > And is there a way to still make this work? Using the new .S3method(<generic>, <class>, <method_function>) had been intended as substitute. Can you try it with your attached-environment (which makes sense!) approach ? Best, Martin
Viechtbauer, Wolfgang (SP)
2020-May-12 19:13 UTC
[Rd] S3 method dispatch for methods in local environments
Indeed, that works: myfun <- function(y) { out <- list(y=y) class(out) <- "myclass" return(out) } myenv <- new.env() myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), new.env(myenv)) .S3method("print", "myclass", myenv$print.myclass) attach(myenv) myfun(1:4) # [1] "1.00000" "2.00000" "3.00000" "4.00000" Thanks for the tip! Best, Wolfgang>-----Original Message----- >From: Martin Maechler [mailto:maechler at stat.math.ethz.ch] >Sent: Tuesday, 12 May, 2020 21:05 >To: Viechtbauer, Wolfgang (SP) >Cc: r-devel (r-devel at r-project.org) >Subject: Re: [Rd] S3 method dispatch for methods in local environments > >>>>>> Viechtbauer, Wolfgang (SP) >>>>>> on Tue, 12 May 2020 18:05:32 +0000 writes: > > > Dear All, > > In R 3.6.3 (and earlier), method dispatch used to work for methods >stored in local environments that are attached to the search path. For >example: > > > myfun <- function(y) { > > out <- list(y=y) > > class(out) <- "myclass" > > return(out) > > } > > > print.myclass <- function(x, ...) print(formatC(x$y, format="f", >digits=5)) > > > myfun(1:4) > > > # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" > > > rm(print.myclass) > > myenv <- new.env() > > myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, >format="f", digits=5)), myenv) > > attach(myenv) > > myfun(1:4) > > > # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" > > > But since R 4.0.0, this no longer words and the above prints: > > > $y > > [1] 1 2 3 4 > > > attr(,"class") > > [1] "myclass" > > > Is this intended? > >yes, most probably, unless > > > And is there a way to still make this work? > >Using the new > > .S3method(<generic>, <class>, <method_function>) > >had been intended as substitute. Can you try it with your >attached-environment (which makes sense!) approach ? > >Best, >Martin
Sebastian Meyer
2020-May-12 19:17 UTC
[Rd] S3 method dispatch for methods in local environments
Dear Wolfgang, I think this new behaviour is related to the following R 4.0.0 NEWS item:> S3 method lookup now by default skips the elements of the search path between the global and base environments.Your environment "myenv" is attached at position 2 of the search() path and thus now skipped in S3 method lookup. I have just noticed that attr(methods(class="myclass"), "info") getS3method("print", "myclass") both still find your function in myenv although the generic's UseMethod() won't. I find this a bit confusing. A solution to make R >= 4.0.0 find your method is to register the S3 method using the new function .S3method (intended for R scripts, not packages). After running .S3method("print", "myclass", myenv$print.myclass) your method will be found from the generic. Best regards, Sebastian Am 12.05.20 um 20:05 schrieb Viechtbauer, Wolfgang (SP):> Dear All, > > In R 3.6.3 (and earlier), method dispatch used to work for methods stored in local environments that are attached to the search path. For example: > > myfun <- function(y) { > out <- list(y=y) > class(out) <- "myclass" > return(out) > } > > print.myclass <- function(x, ...) print(formatC(x$y, format="f", digits=5)) > > myfun(1:4) > > # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" > > rm(print.myclass) > myenv <- new.env() > myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), myenv) > attach(myenv) > myfun(1:4) > > # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" > > But since R 4.0.0, this no longer words and the above prints: > > $y > [1] 1 2 3 4 > > attr(,"class") > [1] "myclass" > > Is this intended? And is there a way to still make this work? > > Best, > Wolfgang > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >
Viechtbauer, Wolfgang (SP)
2020-May-12 21:35 UTC
[Rd] S3 method dispatch for methods in local environments
Thanks, Sebastian, for the pointer to the NEWS item. After some further search, I also found this in the R Blog: https://developer.r-project.org/Blog/public/2019/08/19/s3-method-lookup/ Best, Wolfgang>-----Original Message----- >From: R-devel [mailto:r-devel-bounces at r-project.org] On Behalf Of Sebastian >Meyer >Sent: Tuesday, 12 May, 2020 21:17 >To: r-devel at r-project.org >Subject: Re: [Rd] S3 method dispatch for methods in local environments > >Dear Wolfgang, > >I think this new behaviour is related to the following R 4.0.0 NEWS item: > >> S3 method lookup now by default skips the elements of the search path >between the global and base environments. > >Your environment "myenv" is attached at position 2 of the search() path >and thus now skipped in S3 method lookup. > >I have just noticed that > >attr(methods(class="myclass"), "info") >getS3method("print", "myclass") > >both still find your function in myenv although the generic's >UseMethod() won't. I find this a bit confusing. > >A solution to make R >= 4.0.0 find your method is to register the S3 >method using the new function .S3method (intended for R scripts, not >packages). After running > >.S3method("print", "myclass", myenv$print.myclass) > >your method will be found from the generic. > >Best regards, > > Sebastian > > >Am 12.05.20 um 20:05 schrieb Viechtbauer, Wolfgang (SP): >> Dear All, >> >> In R 3.6.3 (and earlier), method dispatch used to work for methods stored >in local environments that are attached to the search path. For example: >> >> myfun <- function(y) { >> out <- list(y=y) >> class(out) <- "myclass" >> return(out) >> } >> >> print.myclass <- function(x, ...) print(formatC(x$y, format="f", >digits=5)) >> >> myfun(1:4) >> >> # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" >> >> rm(print.myclass) >> myenv <- new.env() >> myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, >format="f", digits=5)), myenv) >> attach(myenv) >> myfun(1:4) >> >> # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000" >> >> But since R 4.0.0, this no longer words and the above prints: >> >> $y >> [1] 1 2 3 4 >> >> attr(,"class") >> [1] "myclass" >> >> Is this intended? And is there a way to still make this work? >> >> Best, >> Wolfgang